JavaScript: индексирование объекта по значениям столбца - PullRequest
0 голосов
/ 15 марта 2012

У меня есть массив таблиц, который выглядит так:

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

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

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

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

Любая помощь или подсказки были бы здесь полезны. Спасибо.

1 Ответ

1 голос
/ 15 марта 2012

Вы упоминаете рекурсию, но не используете ее в своем коде.Это классическая ситуация, когда рекурсия - правильный инструмент.Вот одна из реализаций:

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/

...