我想基于另外两个数组创建下一个数组:
array1 = ['a', 'b']
array2 = [1,2,3]
我想创建下一个数组
newArray = [['a',1], ['a',2], ['a',3], ['b',1], ['b',2], ['b',3]]
这是我的代码:
var test1 = ['a', 'b'];
var test2 = [1,2,3], arr1 = [], arr2 = [];
for(var i = 0; i < test1.length; i++){
arr1 = [];
arr1.push(test1[i]);
for(var x = 0; x < test2.length; x++){
if(arr1.length > 1)
arr1.pop();
arr1.push(test2[x])
arr2.push(arr1);
}
}
console.log("arr1:",JSON.stringify(arr1), "arr2:" ,JSON.stringify(arr2));
&#13;
但它返回第二个数组的最后一个元素。
[['a',3], ['a',3], ['a',3], ['b',3], ['b',3], ['b',3]]
为什么会这样?
答案 0 :(得分:5)
关于数组长度的所有其他答案,以及类似的事情都是不对的。你得到3
(或任何最后的值/长度)的唯一原因是因为数组是引用的,而functions
,而不是for-loops
创建词法范围。这是你听说'功能是javascript中的一等公民'的原因之一。这是一个经典的例子,并且经常在采访中,用来惹恼那些不熟悉javascript范围内的范围的开发人员。有一些方法可以修复它,包括在函数范围内包装循环内部,并传入索引,但我想建议一个更“以javascript为中心”的方法,那就是解决函数问题。 / p>
请参阅此示例(顺便提一下,这也是实现目标的明确方法。)
var test1 = ['a', 'b'];
var test2 = [1,2,3];
// this will iterate over array 1 and return
// [[ [a,1],[a,2],[a,3] ],[ [b,1],[b,2],[b,3] ]]
var merged = test1.map(function(item1){
return test2.map(function(item2){
return [item1, item2];
});
});
//this is a slick way to 'flatten' the result set
var answer = [].concat.apply([],merged )
console.log(answer) //this is it.
函数()
使范围 - 而不是'括号'{}
。最简单的解决方法通常是使用函数来解决问题,因为它们会创建词法范围。例如,npm上最受信任的库,lodash就是基于此。我认为随着你的进步,你会逐日编写越来越少的循环,并使用更多功能。
关于js小提琴的工作示例: https://jsfiddle.net/3z0hh12y/1/
您可以在此处详细了解范围和闭包 https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch1.md
还有一件事:当你认为你想要一个循环js时,你通常需要Array.map()
,特别是如果你正在重新映射值。
答案 1 :(得分:0)
它的发生是因为一旦它的长度超过1,你就会从arr1中弹出元素,所以最后一个元素就是这一点。
试试这个:
var test1 = ['a', 'b'];
var test2 = [1,2,3];
var arr1 = [], arr2 = [];
for(var i = 0; i < test1.length; i++) {
for(var x = 0; x < test2.length; x++) {
arr1[arr1.length] = [test1[i], test2[x]];
}
}
console.log(JSON.stringify(arr1));
&#13;
答案 2 :(得分:0)
你的问题在于第二个循环。因为你对ary1有一个引用,所以你在每个循环中都要写入值。
所以第一次循环你的数组会有
[['a',1]]
但是因为你只有一个对ary1的引用,你只是在编辑你刚推入ary2的值。
所以你得到这个:
[['a',2],['a',2]]
您可能认为您正在推送一个新阵列,但它实际上是完全相同的阵列!所以模式继续,你得到你所看到的结果。
答案 3 :(得分:0)
除了针对两个数组的固定样式的解决方案之外,您可以使用另一种方法来获得结果。您可以使用迭代和递归方法来获取可变长度的零件长度。
function combine(array) {
function c(part, index) {
array[index].forEach(function (a) {
var p = part.concat([a]);
if (p.length === array.length) {
r.push(p);
return;
}
c(p, index + 1);
});
}
var r = [];
c([], 0);
return r;
}
console.log(combine([['a', 'b'], [1, 2, 3]]));
console.log(combine([['a', 'b', 'c'], ['1', '2', '3', '4'], ['A', 'B']]));
console.log(combine([['a', 'b', 'c'], ['1', '2', '3', '4'], [['A'], ['B']]]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 4 :(得分:0)
我想正确的功能方法可以通过单个衬垫reduce和嵌套的map duo来完成。
var arr = ['a', 'b'],
brr = [1,2,3],
result = arr.reduce((p,c) => p.concat(brr.map(e => [c,e])),[]);
console.log(JSON.stringify(result));
答案 5 :(得分:-1)
你的方法有点偏离,你最好采用这种方法(我认为这非常简单): DEMO
var array1 = ['a', 'b'],
array2 = [1,2,3],
nextArray=[];
for(var i=0, array1Length=array1.length; i < array1Length; i++){
for(var x=0, array2Length=array2.length; x < array2Length; x++){
nextArray.push([array1[i],array2[x]]);
}
}
console.log(nextArray);
答案 6 :(得分:-1)
我修改了你的代码(但不是太多,我试图保持相同的方法)。解决方案是在内部循环中创建一个新数组(arr1
)。否则,第一个正确的对['a', 1]
将在下一个循环传递开始推送到arr2
后被覆盖。
var test1 = ['a', 'b'];
var test2 = [1,2,3];
var arr2 = [];
for(var i = 0; i < test1.length; i++){
for(var x = 0; x < test2.length; x++){
var arr1 = [];
arr1.push(test1[i]);
if(arr1.length > 1){
arr1.pop();
}
arr1.push(test2[x]);
arr2.push(arr1);
}
}
答案 7 :(得分:-1)
是的,这种方式比它需要的更复杂。您想要的结果称为Cartesian product,可以像这样生成:
const cartesianProduct = (a, b) => {
const rv = [];
a.map(ae => b.map(be => rv.push([ae, be])));
return rv;
};
const array1 = ['a', 'b']
const array2 = [1,2,3]
console.log(JSON.stringify(cartesianProduct(array1, array2)));
&#13;
如果Javascript6有flatMap
,那就更简单了:
const cartesianProduct = (a, b) =>
a.flatMap(ae => b.map(be => [ae, be]));