减少一个数组的数组(Javascript)

huangapple go评论54阅读模式
英文:

Reduce an array of arrays (Javascript)

问题

我有一个数组的数组,即:
const arrayDaddy = [[x, 1], [x, 1], [y, 2], [y, 2], [y, 2], [z, 3]]

我的最终目标是通过在具有相同值的两个项arrayDaddy[i][0]中添加arrayDaddy[i][1]中的数字来改变arrayDaddy。此外,我想在它们被添加后丢弃具有重复的arrayDaddy[i][0]值的嵌套数组。在arrayDaddy上执行此过程的期望结果如下:

arrayDaddy = [[x, 2], [y, 6], [z, 3]]

我想知道是否有一种方法可以使用 Array.prototype.reduce(); 来实现这个目标。如果不行,有什么简单的方法可以实现这个目标?

注意:不确定是否重要,但所有具有相同值的索引0中的项目将共享索引1中的值。例如,请考虑 [z, 3]。任何附加的 [z, ] 项目也将在索引1中具有3。

我尝试过 reduce(); 但没有成功。我的代码看起来像这样:

const arrayDaddy = [[x, 1], [x, 1], [y, 2], [y, 2], [y, 2], [z, 3]];

arrayDaddy.reduce((arr1, arr2) => {
  if(arr1[0] === arr2[0]){
    arr1[1] += arr2[1]
    // 在这里做一些事情来删除 arr2... 但是我不能在局部变量上使用 delete 吗?
  } else {
    // 什么都不做,继续下一个 arrDaddy 中的项
  }
});

我还考虑了 map,但希望避免创建一个新数组。我想改变 arrayDaddy

英文:

I have an array of arrays i.e:
const arrayDaddy = [[x, 1], [x, 1], [y, 2], [y, 2], [y, 2], [z, 3]]

my end goal is to take the above arrayDaddy and mutate it by adding the number in arrayDaddy[i][1] if the two items have the same value arrayDaddy[i][0]. Additionally, I want to throw out nested arrays with repeated arrayDaddy[i][0] values after they have been added. The desired result of this process on arrayDaddy would be as follows:

arrayDaddy = [[x, 2], [y, 6], [z, 3]]

I am wondering if there is a way to use Array.prototype.reduce(); to achieve this. If not, what is a simple way to achieve this goal?

NOTE: not sure if this is important, but all items with the same value in index 0 will share an index 1 value. for example consider [z, 3]. any addition [z, ] items will also have a 3 in index 1.

I did try reduce(); but did not have success. my code looked something like this:

const arrayDaddy = [[x, 1], [x, 1], [y, 2], [y, 2], [y, 2], [z, 3]] ;

arrayDaddy.reduce((arr1, arr2) => {
  if(arr1[0] === arr2[0]){
    arr1[1] += arr2[1]
    // do something here to delete arr2... but I can't use delete on a local variable?
  } else {
    //do nothing, continue to the next arr in arrayDaddy
  }
});

I also considered map, but want to avoid creating a new array. I want to mutate the arrayDaddy

答案1

得分: 1

你可以使用 reduce 来生成结果。首先,你需要按子数组的第一个元素作为键来存储值,例如使用 Map。然后,在 reduce 过程中更新 Map,当完成时将其转换为一个 Array

注意:Map 中的元素是按键的创建顺序排序的。

使用 Map

const arrayDaddy = [["x", 1], ["x", 1], ["y", 2], ["y", 2], ["y", 2], ["z", 3]];

const res = Array.from(arrayDaddy.reduce((p, c) => {
    const prevVal = p.get(c[0]) || 0;
    p.set(c[0], prevVal + c[1])
    return p;
}, new Map()));

console.log(res);

不使用 Map

如果你真的不想使用 Map,你需要在一个对象中存储子数组的引用。

const arrayDaddy = [["x", 1], ["x", 1], ["y", 2], ["y", 2], ["y", 2], ["z", 3]];

// _tmp 用于存储引用,_idx 用于当前循环索引
let _tmp = {};
let _idx = 0;
while (_idx < arrayDaddy.length) {
    // 获取当前元素
    const element = arrayDaddy[_idx];

    // 如果项目未存储,必须存储并跳过元素
    if (_tmp[element[0]] === undefined) {
        _tmp[element[0]] = element;
        ++_idx;
        continue;
    }

    // 更新值并删除数组元素
    _tmp[element[0]][1] += element[1];
    arrayDaddy.splice(_idx, 1);
}

console.log(arrayDaddy);

不存储引用值

如果你不想存储任何引用以节省内存,你必须迭代每个元素并检查是否有前一个元素以便能够累加当前值并删除当前元素。

const arrayDaddy = [["x", 1], ["x", 1], ["y", 2], ["y", 2], ["y", 2], ["z", 3]];

// _idx 为1,因为你不需要处理第0个元素
let _idx = 1;
while (_idx < arrayDaddy.length) {
    // 获取当前元素
    const element = arrayDaddy[_idx];

    // 检查是否有前一个元素
    let prevFind = false;
    for (let pi = _idx - 1; pi >= 0; --pi) {
        // 如果找到,更新值,删除数组元素,并设置 prevFind 标志
        if (arrayDaddy[pi][0] === element[0]) {
            arrayDaddy[pi][1] += element[1];
            arrayDaddy.splice(_idx, 1);
            prevFind = true;
            break;
        }
    }

    // 没有前一个值,继续下一个
    if (!prevFind) {
        ++_idx;
    }
}

console.log(arrayDaddy);
英文:

You could use reduce to generate. First you must store the values by the key who is the first element of the subarray. For example, with Map. So you will update the Map in the reduce and when is completed transform it to an Array.

NOTE: The elements of the Map are ordered by the creation of their key.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const arrayDaddy = [[&quot;x&quot;, 1], [&quot;x&quot;, 1], [&quot;y&quot;, 2], [&quot;y&quot;, 2], [&quot;y&quot;, 2], [&quot;z&quot;, 3]];

const res = Array.from(arrayDaddy.reduce((p, c) =&gt; {
	const prevVal = p.get(c[0]) || 0;
	p.set(c[0], prevVal + c[1])
	return p;
}, new Map()));

console.log(res);

<!-- end snippet -->

No Map

If you really don't want use Map you must need to store a reference of subarrays in an object.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const arrayDaddy = [[&quot;x&quot;, 1], [&quot;x&quot;, 1], [&quot;y&quot;, 2], [&quot;y&quot;, 2], [&quot;y&quot;, 2], [&quot;z&quot;, 3]];

// _tmp is to store the reference and _idx the current loop index
let _tmp = {};
let _idx = 0;
while (_idx &lt; arrayDaddy.length) {
	// Get current element
	const element = arrayDaddy[_idx];

	// If the item is not stored, must store and skip the element
	if (_tmp[element[0]] === undefined) {
		_tmp[element[0]] = element;
		++_idx;
		continue;
	}

	// Update value and drop array element
	_tmp[element[0]][1] += element[1];
	arrayDaddy.splice(_idx, 1);
}

console.log(arrayDaddy);

<!-- end snippet -->

No store reference values

If you don't want to store any references to save memory you must iterate each element and check if has a previus one to the index to be able to sum the current value and drop the current element.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const arrayDaddy = [[&quot;x&quot;, 1], [&quot;x&quot;, 1], [&quot;y&quot;, 2], [&quot;y&quot;, 2], [&quot;y&quot;, 2], [&quot;z&quot;, 3]];

// _idx is one because you don&#39;t need process the 0 element
let _idx = 1;
while (_idx &lt; arrayDaddy.length) {
	// Get current element
	const element = arrayDaddy[_idx];

	// Check if has previous element
	let prevFind = false;
	for (let pi = _idx - 1; pi &gt;= 0; --pi) {
		// If find, update value, drop array element and set prevFind flag
		if (arrayDaddy[pi][0] === element[0]) {
			arrayDaddy[pi][1] += element[1];
			arrayDaddy.splice(_idx, 1);
			prevFind = true;
			break;
		}
	}

	// No previuos value, go next
	if (!prevFind) {
		++_idx;
	}
}

console.log(arrayDaddy);

<!-- end snippet -->

答案2

得分: 1

如果您在序列中有相同的组,您可以检查最后一组并添加该值。

const
    [x, y, z] = 'xyz';
    array = [[x, 1], [x, 1], [y, 2], [y, 2], [y, 2], [z, 3]],
    result = array.reduce((r, [k, v]) => {
        if (r.at(-1)?.[0] === k) r.at(-1)[1] += v;
        else r.push([k, v]);
        return r;
    }, []);

console.log(result);

这段代码用于处理具有相同组的数组,并将相同组的值相加。

英文:

If you have same groups in sequences, you could check the last group and add the value.

<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const
[x, y, z] = 'xyz';
array = [[x, 1], [x, 1], [y, 2], [y, 2], [y, 2], [z, 3]],
result = array.reduce((r, [k, v]) => {
if (r.at(-1)?.[0] === k) r.at(-1)[1] += v;
else r.push([k, v]);
return r;
}, []);

console.log(result);

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月23日 22:57:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75546526.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定