简体   繁体   English

对javascript上的数组感到困惑

[英]Confused about arrays on javascript

I want to make the next array based on another 2 arrays: 我想基于另外两个数组创建下一个数组:

array1 = ['a', 'b']
array2 = [1,2,3]

I want to create the next array 我想创建下一个数组

newArray = [['a',1], ['a',2], ['a',3], ['b',1], ['b',2], ['b',3]]

Here is my code: 这是我的代码:

  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)); 

But it returns the last element of the second array. 但它返回第二个数组的最后一个元素。

[['a',3], ['a',3], ['a',3], ['b',3], ['b',3], ['b',3]]

Why is this happening? 为什么会这样?

Every other answer about array lengths, and similar things are not right. 关于数组长度的所有其他答案以及类似的事情都是不对的。 The only reason you get 3 (or whatever the last value/length is) all over the place is because Arrays are by reference, and functions , not for-loops create lexical scope. 你得到3 (或任何最后的值/长度)的唯一原因是因为数组是引用,而functions ,而不是for-loops创建词法范围。 This is one of the reasons you hear that 'functions are first-class citizens in javascript'. 这是你听说'功能是javascript中的一等公民'的原因之一。 This is a classical example, and frequently in interviews too, used to trip up devs who are not used to how scoping in javascript really behaves. 这是一个经典的例子,并且经常在采访中,用来惹恼那些不熟悉javascript范围内的范围的开发人员。 There are some ways to fix it that involve wrapping the innards of loops in functional scopes, and passing in the index, but I'd like to suggest a more 'javascript centric' approach, and that is to solve the problem with functions. 有一些方法可以修复它,包括在函数范围内包装循环内部,并传入索引,但我想建议一个更“以javascript为中心”的方法,那就是解决函数问题。

See this example (which by the way is also a clear way to implement your goal.) 请参阅此示例(顺便提一下,这也是实现目标的明确方法。)

 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. 

Functions () make scope - not 'brackets' {} . 函数()使范围 - 而不是'括号' {} The easiest fix is usually to use functions to solve your problems as they create lexical scope. 最简单的解决方法通常是使用函数来解决问题,因为它们会创建词法范围。 The most trusted library on npm, lodash, for instance is based on this. 例如,npm上最受信任的库,lodash就是基于此。 I think you'll write less and less loops from day to day js as you progress, and use more functions. 我认为随着你的进步,你每天都会写越来越少的循环,并使用更多的功能。

Working example on js fiddle: https://jsfiddle.net/3z0hh12y/1/ 关于js小提琴的工作示例: https//jsfiddle.net/3z0hh12y/1/

You can read more about scopes and closures here https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch1.md 您可以在这里阅读有关范围和闭包的更多信息https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch1.md

And one more thing: when you think you want a loop in js, you usually want Array.map() , especially if you're remapping values. 还有一件事: 当你认为你想要一个循环js时,你通常需要Array.map() ,特别是如果你正在重新映射值。

It's occurring because you're popping elements off arr1 once it's length exceeds 1, so the last element is all that persists. 之所以发生这种情况,是因为一旦长度超过1,你就会从arr1中弹出元素,所以最后一个元素就是持续存在。

Try this: 尝试这个:

 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)); 

You problem lies in the second loop. 你的问题在于第二个循环。 because you have a single reference to ary1 you are over writing the value with each loop. 因为你对ary1有一个引用,所以你在每个循环中都要写入值。

so first time it loops your array will have 所以第一次循环你的数组将有

[['a',1]]

but because you you only have one reference to ary1 you are just editing the value you just pushed into ary2. 但是因为你只有一个对ary1的引用,你只需要编辑你刚推入ary2的值。

so then you get this: 所以你得到这个:

[['a',2],['a',2]]

you may think that you are pushing a new array in but it is in fact the same exact array! 你可能会认为你正在推动一个新阵列,但它实际上是完全相同的阵列! so the pattern continues and you get the result that you are seeing. 所以模式继续,你得到你所看到的结果。

Beside the solutions for fixed style for two array, you might use another approach to get the result. 除了针对两个数组的固定样式的解决方案之外,您可以使用另一种方法来获得结果。 you could use an iterative and recursive approach for variable length of parts an their length. 你可以使用迭代和递归方法来获得可变长度的零件长度。

 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; } 

I guess the proper functional approach would be done by a single liner reduce and nested map duo. 我想正确的功能方法将通过单个衬垫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)); 

your approach is a bit off, you better take this approach (which is pretty simple I think): DEMO 你的方法有点偏,你最好采用这种方法(我认为这很简单): 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);

I modified your code a little (but not too much, I tried to keep the same approach). 我修改了你的代码(但不是太多,我试图保持相同的方法)。 The solution was to create a new array ( arr1 ) in the inner loop. 解决方案是在内部循环中创建一个新数组( arr1 )。 Otherwise, the first correct pair ['a', 1] would get overridden just after begin pushed to arr2 at the next loop pass. 否则,第一个正确的对['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);
    }
}

Yeah, that's way more complicated than it needs to be. 是的,这比它需要的更复杂。 The result you want is called the Cartesian product , and can be generated like this: 您想要的结果称为笛卡尔积 ,可以像这样生成:

 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))); 

If Javascript6 had flatMap it would be even simpler: 如果Javascript6有flatMap它会更简单:

 const cartesianProduct = (a, b) => 
    a.flatMap(ae => b.map(be => [ae, be]));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM