检查 Ticker 是否在另一个列表中,然后添加一个新键 [RamdaJS]

Checking if Ticker is in another list, then adding a new key [RamdaJS]

我正在尝试使用 Ramda 比较 2 个列表,找出 tickersList 中的哪些代码也在 portfolioTickers 中。如果投资组合列表中也有一个,则添加一个关键字 portfolio:true

示例数据:

tickers = [
    { ticker: aa },
    { ticker: bb },
    { ticker: cc }
]

portfolio = [
    { ticker: aa }
]

预期结果:

tickers = [
    { ticker: aa, portfolio: true },
    { ticker: bb },
    { ticker: cc }
]

听起来很简单,但到目前为止卡在这里:

const checkTicker = _.curry((ticker, portTicker) => {
    if (ticker.ticker === portTicker.ticker) {
        ticker.portfolio = true;
    }
    return ticker;
});

const matched = R.anyPass([checkTicker]);

const setPortfolioFlag = _.curry((portfolioTickers, ticker) => {
    // const matched = R.filter(checkTicker(ticker), portfolioTickers);
    // console.log('matched', matched)
    const each = matched(R.forEach(checkTicker(ticker), portfolioTickers));
    console.log('each', each)

    return each;
});

const inPortfolioCheck = (tickersList) => {
    const portfolioTickers = R.filter(TickersFactory.isTickerInPortfolio, tickersList);
    const tickers = R.map(setPortfolioFlag(portfolioTickers), tickersList);
    console.log('tickers', tickers)
};

const displayTickers = (tickers) => {
    this.tickersList = tickers; 
    const checkedTickers = inPortfolioCheck(this.tickersList);
    console.log('checkedTickers', checkedTickers)
};

现在 each 始终为真,所有这些逻辑的列表 returns 只是一个与我的 tickerList 长度相同的列表,但只是 true'.

我一直 运行 关注的一个问题是我觉得我需要 运行 另一个 R.map 来进行检查,但是返回的地图的结果是 Portfolio代码,而不是原始列表。


工作代码,但有一个丑陋的 for 循环:

这显然有效,因为我使用的是 for 循环,但我试图删除所有面向对象的代码并替换为功能代码。

const setPortfolioFlag = _.curry((portfolioTickers, ticker) => {
    for (var i=0; i<portfolioTickers.length; i++) {
        if (portfolioTickers[i].ticker === ticker.ticker) {
            ticker.portfolio = true;
        }
    }

    return ticker;
});

const inPortfolioCheck = (tickersList) => {
    const portfolioTickers = R.filter(TickersFactory.isTickerInPortfolio, tickersList);
    return R.map(setPortfolioFlag(portfolioTickers), tickersList);
};

const displayTickers = (tickers) => {
    this.tickersList = inPortfolioCheck(tickers);
    console.log('this.tickersList', this.tickersList)
};

forLoop 的 LoDash 版本:

_.each(portfolio, (port) => {
    if (port.ticker === ticker.ticker) {
        ticker.portfolio = true;
    }
});

所以您可能首先注意到的是预期结果 tickers 数组与输入 tickers 数组相同 "shape",这表明我们应该能够利用R.map 的表达式。知道了这一点,我们就可以专注于数组的各个元素必须发生的事情。

因此,对于每个代码对象,当在 portfolio 数组中找到时,我们想附加 portfolio: true 属性.

const updateTicker =
  R.when(R.flip(R.contains)(portfolio), R.assoc('portfolio', true))

updateTicker({ ticker: 'aa' })
//=> {"portfolio": true, "ticker": "aa"}

updateTicker({ ticker: 'bb' })
//=> {"ticker": "bb"}

然后我们只需映射代码列表即可更新每个代码。

R.map(updateTicker, tickers)
//=> [{"portfolio": true, "ticker": "aa"}, {"ticker": "bb"}, {"ticker": "cc"}]

@scott-christopher 的回答一如既往地出色。但随后的评论让我认为它并没有完全涵盖您的用例。如果数据更复杂,并且 portfoliotickers 中的项目可能具有不同的属性,那么 contains 就不够强大。因此,如果您的数据看起来更像这样:

const tickers = [
    { ticker: 'aa', size: 1 },
    { ticker: 'bb', size: 2 },
    { ticker: 'cc', size: 3 },
    { ticker: 'dd', size: 4 }
]

const portfolio = [
    { ticker: 'aa', id: 'abc' },
    { ticker: 'dd', id: 'xyz' }
]

那么这个版本可能会更好:

const updateTicker =
  when(pipe(eqProps('ticker'), any(__, portfolio)), assoc('portfolio', true))

这个几乎没有积分的版本可能有点晦涩难懂。相当于这个:

const updateTicker =
    when(
        (ticker) => any(eqProps('ticker', ticker), portfolio), 
        assoc('portfolio', true)
    )

还有,如果any(__, portfolio)写法不清楚,相当于flip(any)(portfolio)

你可以在Ramda REPL上看到这个。