具有谓词的对象数组的惯用和功能JS减少

时间:2015-11-16 12:13:32

标签: javascript arrays functional-programming reduction

来自代表股票的对象数组,其现货价格和其他属性,如

stocks = [ { ticker: 'GOOG', price: 206, ... },
           { ticker: 'AAPL', price: 47, ... },
           { ticker: 'MSFT', price: 39, ... },
           { ticker: 'GOOG', price: 159, ... },
           { ticker: 'MSFT', price: 39, ... },
           { ticker: 'MSFT', price: 21, ... },
           { ticker: 'GOOG', price: 80, ... },
           { ticker: 'AAPL', price: 20, ... },
           { ticker: 'AAPL', price: 73, ... },
           { ticker: 'MSFT', price: 49, ... },
           ... ];

我想为每个自动收报机返回一个简化数组,其中包含具有最大价格(和其他属性)的对象。

这是我到目前为止所拥有的:

c.reduce(function(acc, y) { 
  return acc
    .filter(function(x) { return x.ticker!=y.ticker })
    .concat(
      acc.filter(function(x) { return x.ticker==y.ticker })
        .concat([y])
        .reduce(function(u,v) { 
          return u.price > v.price ? u : v } ) /* predicate */
    )  
}, []);

但是有更惯用的JavaScript方法吗? Underscore和lodash是受欢迎的,但请不要jQuery。

3 个答案:

答案 0 :(得分:0)

用lodash:

var res = _(stocks)
    // group all elements by 'ticker'
    .groupBy(function (s) {
        return s.ticker;
    // sort each group by price descending and get the first element (the max)
    }).map(function (n) {
        return _(n).sortBy(n, function (v) {
            return -v.price;
        }).first();
    });

console.log(JSON.stringify(res, null, 4));

该代码给出:

[
    {
        "ticker": "GOOG",
        "price": 206
    },
    {
        "ticker": "AAPL",
        "price": 73
    },
    {
        "ticker": "MSFT",
        "price": 49
    }
]

更短版本排序ASC并获取最后一个元素:

var res = _(stocks)
    .groupBy('ticker')
    .map(function (n) {
        return _(n).sortBy('price').last();
    });

答案 1 :(得分:0)

我尝试用功能概念解决这个问题。

var stocks =
  [
   {ticker: 'GOOG', price: 206},
   {ticker: 'AAPL', price: 47},
   {ticker: 'MSFT', price: 39},
   {ticker: 'GOOG', price: 159},
   {ticker: 'MSFT', price: 39},
   {ticker: 'MSFT', price: 21},
   {ticker: 'GOOG', price: 80},
   {ticker: 'AAPL', price: 20},
   {ticker: 'AAPL', price: 73},
   {ticker: 'MSFT', price: 49}
 ];

var result = stocks.reduce(function (acc, next) {
  return acc
        .filter(function (stock) {
           return stock.ticker != next.ticker
        })
        .concat(acc.reduce(function (u, v) {
           return u.ticker == v.ticker && u.price < v.price ? v : u;
        }, next));
}, []);


console.log(result);

输出

[ 
 { ticker: 'GOOG', price: 206 },
 { ticker: 'AAPL', price: 73 },
 { ticker: 'MSFT', price: 49 } 
]

答案 2 :(得分:0)

这是一个纯JavaScript解决方案,没有任何只使用一个filter()和一个reduce()的框架:

<强>代码

var stocks = [ { ticker: 'GOOG', price: 206},
           { ticker: 'AAPL', price: 47},
           { ticker: 'MSFT', price: 39},
           { ticker: 'GOOG', price: 159},
           { ticker: 'MSFT', price: 39},
           { ticker: 'MSFT', price: 21},
           { ticker: 'GOOG', price: 80},
           { ticker: 'AAPL', price: 20},
           { ticker: 'AAPL', price: 73},
           { ticker: 'MSFT', price: 49}];

function max(arr) {
  return arr.filter(function(item){
    return this[item.ticker] === item;
  }.bind(arr.reduce(function(res, cur) {
    return (res[cur.ticker] = (res[cur.ticker] 
        ? (res[cur.ticker].price > cur.price ? res[cur.ticker] : cur)
        : cur
    )), res;
  }, {})));
}

console.log(max(stocks));

<强>结果

[ 
 { ticker: 'GOOG', price: 206 },
 { ticker: 'AAPL', price: 73 },
 { ticker: 'MSFT', price: 49 } 
]

<强> JSBin

https://jsbin.com/linevudika/edit?js,console