簡體   English   中英

對javascript上的數組感到困惑

[英]Confused about arrays on javascript

我想基於另外兩個數組創建下一個數組:

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

但它返回第二個數組的最后一個元素。

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

為什么會這樣?

關於數組長度的所有其他答案以及類似的事情都是不對的。 你得到3 (或任何最后的值/長度)的唯一原因是因為數組是引用,而functions ,而不是for-loops創建詞法范圍。 這是你聽說'功能是javascript中的一等公民'的原因之一。 這是一個經典的例子,並且經常在采訪中,用來惹惱那些不熟悉javascript范圍內的范圍的開發人員。 有一些方法可以修復它,包括在函數范圍內包裝循環內部,並傳入索引,但我想建議一個更“以javascript為中心”的方法,那就是解決函數問題。

請參閱此示例(順便提一下,這也是實現目標的明確方法。)

 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,你就會從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)); 

你的問題在於第二個循環。 因為你對ary1有一個引用,所以你在每個循環中都要寫入值。

所以第一次循環你的數組將有

[['a',1]]

但是因為你只有一個對ary1的引用,你只需要編輯你剛推入ary2的值。

所以你得到這個:

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

你可能會認為你正在推動一個新陣列,但它實際上是完全相同的陣列! 所以模式繼續,你得到你所看到的結果。

除了針對兩個數組的固定樣式的解決方案之外,您可以使用另一種方法來獲得結果。 你可以使用迭代和遞歸方法來獲得可變長度的零件長度。

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

我想正確的功能方法將通過單個襯墊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)); 

你的方法有點偏,你最好采用這種方法(我認為這很簡單): 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);

我修改了你的代碼(但不是太多,我試圖保持相同的方法)。 解決方案是在內部循環中創建一個新數組( 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);
    }
}

是的,這比它需要的更復雜。 您想要的結果稱為笛卡爾積 ,可以像這樣生成:

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

如果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