2012-03-15 2 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} 
     } 
} 

So

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

Если число столбцов в массиве имен столбцов ([ 'столбец1', 'столбец2'] выше) известно, решение не сложно. Но если я разрешу для любого количества имен столбцов в этом массиве, становится все труднее, поскольку есть неопределенные рекурсии

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

Вот одна попытки. Я попытался использовать указатель, чтобы указать на размерную глубину массива newObject. Сначала указатель = 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

+1

Не должен ли внутренний объект в вашем результате быть массивом, который содержит каждый объект с соответствующим значением столбца один? – jfriend00

+0

@ jfriend00 Для моих целей, поскольку комбинация значений столбцов, которые я ожидаю использовать, будет уникальной, внутренний массив не понадобится. –

ответ

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

Это прекрасно работает. Спасибо. Я делал это сложнее, чем нужно; использование рекурсивной функции определенно помогает. –

Смежные вопросы