JavaScript:如何将对象数组转换为具有排序唯一数组的对象?

5

您好,需要处理这种类型的数据结构:

$input = [ { animal: 'cat', name: 'Rocky', value: 1 },
           { animal: 'cat', name: 'Spot',  value: 2 },
           { animal: 'dog', name: 'Spot',  value: 3 } ];

需要最快的方法将内容转换为以下格式:
$output = { animal: [ 'cat', 'dog' ],
            name: [ 'Rocky', 'Spot' ],
            value: [ 1, 2, 3 ] };

输出的键应与输入中每个对象的键相等。输出值应该是排序后唯一值的数组。我找到了一些使用嵌套循环的方法,但速度比我想象的要慢。在输入数组中有30,000个元素,每个对象有8个键,我能做到的最好的时间是Chrome上的300毫秒。希望能够降低到100毫秒。是否有更快的方法可以使用映射或缩减?


5
为什么不发布你目前拥有的内容呢?这似乎就像将值推入数组一样简单,然后在最后进行去重和排序。 - Tejs
这总是时空权衡和效率的问题。你可以用空间来换取时间。 - Darin Dimitrov
请记住,$不是JavaScript - 这是PHP变量。嵌套循环是你能得到的最好的结果 - 那是你在那里拥有的全部。为什么要以那种方式改变结构?输入似乎更合理和可用。 - Bradley
@Bradley:不正确。$something是Javascript中有效的变量名。你认为jQuery是如何工作的? - Elliot Bonneville
嵌套循环并不是他能够得到的最好解决方案。正如我所说,他可以通过在单个循环中交换空间和时间来完成这个任务。 - Darin Dimitrov
5个回答

3

现代浏览器的另一种方式:

$input.reduce(function(acc, obj) {
  Object.keys(obj).forEach(function(k) {
    acc[k] = (acc[k] || []).concat(obj[k])
  })
  return acc
},{})

这是使用函数式编程的“下划线”方式!这应该是最佳答案! - Gaurav Ramanan

2
这是一种方法。
$input = [ { animal: 'cat', name: 'Rocky', value: 1 },
           { animal: 'cat', name: 'Spot',  value: 2 },
           { animal: 'dog', name: 'Spot',  value: 3 } ];

$output = {animal:{},name:{},value:{}};

$input.forEach(function(v,i) { 
    $output.animal[v.animal] = 1;
    $output.name[v.name] = 1;
    $output.value[v.value] = 1;
});

$output.animal = Object.keys($output.animal);
$output.name = Object.keys($output.name);
$output.value = Object.keys($output.value);

它可以避免每次测试每个数组,您可以进行性能比较以查看是否有帮助。

实时示例:http://jsfiddle.net/TJVtj/1/


如果您不想硬编码键,则可以使解决方案通用。

var keys = Object.keys($input[0]),
    $output = {};

keys.forEach(function(v) {
    $output[v] = {};
});

$input.forEach(function(v) {
    keys.forEach(function(vv) {
        $output[vv][v[vv]] = 1;
    });
});

keys.forEach(function(v) {
    $output[v] = Object.keys($output[v]);
});

实时例子:http://jsfiddle.net/TJVtj/2/

警告。所有值都将作为对象键而被获取,因此它们都将是字符串。


0
function inArray(needle, haystack) {
    var length = haystack.length;
    for(var i = 0; i < length; i++) {
        if(haystack[i] == needle) return true;
    }
    return false;
}

上述函数用于检查重复项。

$output={};
for(i=0; i< $input.length; i++)
{
    if(!$output.animal) $output.animal=[];
    if(!$output.name) $output.name=[];
    if(!$output.value) $output.value=[];
    var ani=$input[i];
    if(ani.animal && !inArray(ani.animal, $output.animal)) $output.animal.push(ani.animal);
    if(ani.name && !inArray(ani.name, $output.name)) $output.name.push(ani.name);
    if(ani.value) $output.value.push(ani.value);
}

演示。


0

// 如果你不知道所有对象都有相同的键,你需要查看每一个-

var output= {},
input= [{
    animal:'cat', name:'Rocky', value:1
},{
    animal:'cat', name:'Spot', value:2
},{
    animal:'dog', name:'Spot', value:3
}];
input.forEach(function(itm){
    for(var p in itm){
        if(itm.hasOwnProperty(p)){
            if(!output[p]) output[p]= [];
            if(output[p].indexOf(itm[p])== -1) output[p].push(itm[p]);
        }
    }
});

Run.expose(output)// nonstandard object to string method

// returned value: (String)
{
    animal:[
        'cat',
        'dog'
    ],
    name:[
        'Rocky',
        'Spot'
    ],
    value:[
        1,
        2,
        3
    ]
}

-1

试试Underscore,它在这种任务中非常出色。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接