2012-03-15 74 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