2016-10-02 205 views
3

陣列我要讓下一個數組基於另一個2個陣列:困惑於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) 
 
     \t 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]] 

爲什麼會發生這種情況?

回答

5

有關數組長度每隔答案,以及類似的東西是不正確的。你得到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]; 
 
    }); \t 
 
    }); 
 

 
//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

不錯的一個!應該是'return [item1,item2]'創建OP所要求的數組嗎? –

+1

讓我仔細檢查一下,看起來像是我在我的小提琴中編輯。現在它已更新。看起來我已經翻過了他們。工作演示和答案應該是正確的。 –

+0

以基準! –

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

你能至少解釋爲什麼它的 '關'?這就是問題所在。 – Li357

0

它的發生,因爲你彈出元素關閉ARR1一旦它的長度超過1 ,所以最後一個元素就是所有這些。

試試這個:

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

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

你問題在於第二個循環。因爲你有一個對ary1的引用,所以你正在寫每個循環的值。

所以第一次循環,你的陣列將有

[['a',1]] 

而是因爲你,你只能有一個參考ary1你只是編輯您剛纔推入ary2值。

,那麼你會得到:

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

,你可能會認爲你正在推動一個新的數組中,但它實際上是完全相同的陣!所以這個模式會繼續下去,你會看到你所看到的結果。

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

如果Javascript6有flatMap它會更簡單:

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

請通過=>語法指導我。 –

+0

@ J.D.Pace這是ES6中的[箭頭函數](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)。 – Li357

+0

這只是使用map作爲外部數組的迭代器。不是很優雅。 – Redu

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

+0

這裏有一個小問題。如果你的數組項是數組,那麼'.concat()'將解包它們。即嘗試'[['a','b','c'],['1','2','3','4'],[['A'],['B']]] '。我在[this one](https://repl.it/DmXN)中有同樣的問題嗎? – Redu

+0

@redu,在上面的例子中,你可以將它們包裝在括號中,比如'var p = part.concat([a]);'也許這對你的問題有幫助(concar只會降低一個級別的陣列)。 –

+0

你在那裏排列所有物品嗎?是的,這是我想過的東西,但對我來說就像一個骯髒的黑客。嗯,不,..在你的情況下,第二個想法是可行的,我想。 – Redu

1

我猜合適的功能的方法是通過一個襯墊進行減少和嵌套地圖二人。

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