从对象数组中提取属性值为数组?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (9)
  • 关注 (0)
  • 查看 (3039)

我有以下结构的JavaScript对象数组:

objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];

我想提取一个包含键值的数组,其中。foo的值[ 1, 3, 5 ]...

我用下面的方法来完成:

function getFields(input, field) {
    var output = [];
    for (var i=0; i < input.length ; ++i)
        output.push(input[i][field]);
    return output;
}

var result = getFields(objArray, "foo"); // returns [ 1, 3, 5 ]

有没有更简单的方法?

提问于
用户回答回答于
用户回答回答于

函数映射是处理对象数组的一个很好的选择

如果要排除值未定义的属性或特定属性,可以执行以下操作:

    var obj = {value1: "val1", value2: "val2", Ndb_No: "testing", myVal: undefined};
    var keysFiltered = Object.keys(obj).filter(function(item){return !(item == "Ndb_No" || obj[item] == undefined)});
    var valuesFiltered = keysFiltered.map(function(item) {return obj[item]});
用户回答回答于

这取决于你对“更好”的定义。

你是想要更简洁,可维护,可以理解,等。你可以使用它。

如果你想它速度更快的话,你可以使用以前的方法。

用户回答回答于

虽然map是一个从对象列表中选择“列”的方法,但它有一个缺点。如果列不存在,它将抛出一个错误。reduce解决方案,可以忽略属性,甚至可以设置默认值。

function getFields(list, field) {
    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  check if the item is actually an object and does contain the field
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        }

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin示例

即使在提供的列表中的不包含字段或对象时,这也是可行的。

如果列表不包含某字段,则可以通过设置默认值。

function getFields(list, field, otherwise) {
    //  reduce the provided list to an array containing either the requested field or the alternative value
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        carry.push(typeof item === 'object' && field in item ? item[field] : otherwise);

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin示例

对于map而言,这是相同的,因为返回的数组将与提供的数组长度相同。(在这种情况下)mapreduce更简单)):

function getFields(list, field, otherwise) {
    //  map the provided list to an array containing either the requested field or the alternative value
    return list.map(function(item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        return typeof item === 'object' && field in item ? item[field] : otherwise;
    }, []);
}

jsbin示例

下面可以让你在这两个方案中进行切换

function getFields(list, field, otherwise) {
    //  determine once whether or not to use the 'otherwise'
    var alt = typeof otherwise !== 'undefined';

    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of 'otherwise' if it was provided
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        }
        else if (alt) {
            carry.push(otherwise);
        }

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin示例

还可以使用Array.concat

function getFields(list, field, otherwise) {
    var alt = typeof otherwise !== 'undefined';

    return list.reduce(function(carry, item) {
        return carry.concat(typeof item === 'object' && field in item ? item[field] : (alt ? otherwise : []));
    }, []);
}

jsbin示例

用户回答回答于

跨浏览器时最好使用一些像lodash或下划线这样的库。

在lodash 中,可以通过以下方法在数组中获取属性的值

_.map(objArray,"foo")

和下划线

_.pluck(objArray,"foo")

两者都会返回 [ 1, 3, 5 ]

用户回答回答于

使用Array.prototype.map:

function getFields(input, field) {
    return input.map(function(o) {
        return o[field];
    });
}

参考上面的链接,了解pre-es5浏览器的shim库。

用户回答回答于

对于JS的解决方案,一个简单的for循环索引就够了

从100000元素数组中提取单个属性

传统循环368次/秒

var vals=[];
for(var i=0;i<testArray.length;i++){
   vals.push(testArray[i].val);
}

ES6for..of循环303次/秒

var vals=[];
for(var item of testArray){
   vals.push(item.val); 
}

Array.prototype.map19次操作/秒

var vals = testArray.map(function(a) {return a.val;});

注:OPS/s更新10/2017。

用户回答回答于

检查Lodash's_.pluck()函数Underscore's_.pluck()函数。在一个函数调用中,两者都完全按照您的要求执行!

var result = _.pluck(objArray, 'foo');

最新:_.pluck()已从Lodash v4.0.0中删除

更新2:在Lodashv 4和4.3版本中,添加了一个新函数,提供了此功能。_.property()返回一个函数,用于获取对象中的属性值。

此外,_.map()现在允许将字符串作为第二个参数传入,该参数被传递到_.property()因此,下面两行代码与上面的前Lodash 4中的代码示例差不多。

var result = _.map(objArray, 'foo');
var result = _.map(objArray, _.property('foo'));

_.property(),因此_.map(),还允许您提供点分隔字符串或数组,以便访问子属性:

var objArray = [
    {
        someProperty: { aNumber: 5 }
    },
    {
        someProperty: { aNumber: 2 }
    },
    {
        someProperty: { aNumber: 9 }
    }
];
var result = _.map(objArray, _.property('someProperty.aNumber'));
var result = _.map(objArray, _.property(['someProperty', 'aNumber']));

_.map()上述示例中的调用将返回[5, 2, 9]...

如果您对函数式编程感兴趣,可以看一下Ramda的 R.pluck()函数

var result = R.pluck('foo')(objArray);  // or just R.pluck('foo', objArray)
用户回答回答于

是的,但它是JavaScript的新特性。在IE8或更高版本中可能不会正常实现。

var result = objArray.map(function(a) {return a.foo;});

参考资料料

扫码关注云+社区

领取腾讯云代金券