2012-03-15 63 views
0

我有一個表陣列看起來像這樣:JavaScript的:由列索引對象的值

tablearray = 
[ 
    {'column1': 1, 'column2': 1, 'column3': 1, 'column4': 2}, 
    {'column1': 1, 'column2': 2, 'column3': 3, 'column4': 4}, 
    {'column1': 2, 'column2': 0, 'column3': 4, 'column4': 6} 
] 

我試圖做一個函數,該函數表陣列和列名的數組,使得由列值索引的新對象。所以

newObject = indexByColumnValues(tablearray, ['column1', 'column2']); 

應導致的對象像

newObject = 
{ 
    1: 
     { 
      1: {'column1': 1, 'column2': 1, 'column3': 1, 'column4': 2}, 
      2: {'column1': 1, 'column2': 2, 'column3': 3, 'column4': 4} 
     } 
    2: 
     { 
      0: {'column1': 2, 'column2': 0, 'column3': 4, 'column4': 6} 
     } 
} 

所以

newObject[1][1]['column3'] = 1 
newObject[1][2]['column4'] = 4 
etc... 

如果列名陣列中的列數([ '列1', '列2']以上)是已知的,解決方案並不難。但是,如果我讓這個陣列中的任何數量的列名的,它變得有無限遞歸

newObject[tablearray[columnNameArray[0]][tablearray[columnNameArray[1]][tablearray[columnNameArray[2]]... 

更加困難這是一個嘗試。我試圖用指針指向newObject數組的維度深度。首先,pointer = newObject。然後指針= newObject [... [0]]。然後,point = newObject [... [0]] [... [1]]。等等。這會正確構建對象,但是我沒有辦法爲newObject [... [0]] ... [... [k]]賦值。

function indexByColumnValues(object, columnNameArray) 
{ 
    var newObject = {}; 

    for(i in object) 
    { 
     var index=[]; 

     for(j in columnNameArray) 
     { 
      index.push(object[i][columnNameArray[j]]); 
     } 

     var pointer = newObject; 

     for(j in index) 
     { 
      if(pointer[index[j]] == undefined) 
      { 
       pointer[index[j]] = {}; 
      } 

      pointer = pointer[index[j]]; 
     } 

     //now pointer points to newObject[index[0]][index[1]]...[index[k]] 
     //but I need to set newObject[...] above to be object[i]. How? 
     //pointer = object[i]; //won't work 
    } 

    return newObject; 
} 

任何幫助或提示將在這裏很大。謝謝。

+0

我不知道你是否要使用圖書館或想從你自己的代碼來學習(這是非常有幫助) ,但是underscore.js有'_.groupBy',它正好符合你的要求。 – pimvdb 2012-03-15 19:21:30

+1

結果中的內部對象不應該是一個數組,它將每個對象與匹配列的一個值保存在一起? – jfriend00 2012-03-15 19:25:49

+0

@ jfriend00就我的目的而言,由於我期望使用的列值組合是獨一無二的,所以內部數組是不必要的。 – 2012-03-15 19:45:11

回答

1

你提到了遞歸,但是你並沒有在你的代碼中使用它。這是遞歸是正確的工具的典型情況。這裏有一個實現:

function indexByColumnValues(table, cols) { 
    // get the column we're indexing 
    var col = cols[0], 
     index = {}, 
     x, val; 
    // find all values 
    for (x=0; x<table.length; x++) { 
     val = table[x][col]; 
     // add to index if necessary 
     if (!index[val]) index[val] = []; 
     // push this row 
     index[val].push(table[x]); 
    } 
    // recurse if necessary 
    if (cols.length > 1) { 
     for (x in index) { 
      if (index.hasOwnProperty(x)) { 
       // pass the filtered table and the next column 
       index[x] = indexByColumnValues(
        index[x], 
        cols.slice(1) 
       ); 
      }     
     } 
    } 
    return index; 
} 

需要注意的是,如@ jfriend00筆記,你想你的索引的「葉子」是匹配的行的數組,而不是一個單一的對象 - 這只是巧合,在您的例子中,你只對於給定的數據和一組列,有一個匹配的行。用法:

indexByColumnValues(tablearray, ['column1','column2']);​ 

輸出:

{ 
    "1":{ 
     "1":[ 
      {"column1":1,"column2":1,"column3":1,"column4":2} 
     ], 
     "2":[ 

      {"column1":1,"column2":2,"column3":3,"column4":4} 
     ] 
    }, 
    "2":{ 
     "0":[ 
      {"column1":2,"column2":0,"column3":4,"column4":6} 
     ] 
    } 
} 

的jsfiddle:http://jsfiddle.net/RRcRM/3/

+0

這工作很好。謝謝。我正在讓它比需要更難;使用遞歸函數肯定有幫助。 – 2012-03-15 19:55:06