在地图期间获取前一个元素的功能方法

问题描述 投票:0回答:5
我有一个数组,我

map

。我需要将当前元素与前一个元素进行比较。我通过比较它们的 
id
 并根据此条件执行不同的操作来检测当前元素是否与前一个元素相同。是否有任何纯粹的函数式方法可以在不进行索引数学的情况下做到这一点? 

items.map((item, index) => { if(item.id === items[index - 1 > 0 ? index - 1 : 0].id) { // do something } else { // do something else } })

代码有效,但我想避免对索引进行数学计算。有什么办法可以做到吗?

javascript functional-programming purely-functional
5个回答
1
投票
reduce() 函数提供了您需要的功能:

items.reduce((previousValue, currentValue) => { if(currentValue.id === previousValue.id) { // do something } else { // do something else } });
    

1
投票
不是一个特别快的实现,但解构赋值使其特别优雅 -

const None = Symbol () const mapAdjacent = (f, [ a = None, b = None, ...more ] = []) => a === None || b === None ? [] : [ f (a, b), ...mapAdjacent (f, [ b, ...more ]) ] const pair = (a, b) => [ a, b ] console.log(mapAdjacent(pair, [ 1, 2, 3 ])) // [ [ 1, 2 ], [ 2, 3 ] ] console.log(mapAdjacent(pair, "hello")) // [ [ h, e ], [ e, l ], [ l, l ], [ l, o ] ] console.log(mapAdjacent(pair, [ 1 ])) // [] console.log(mapAdjacent(pair, [])) // []

或者将其写为生成器 -

const mapAdjacent = function* (f, iter = []) { while (iter.length > 1) { yield f (...iter.slice(0,2)) iter = iter.slice(1) } } const pair = (a, b) => [ a, b ] console.log(Array.from(mapAdjacent(pair, [ 1, 2, 3 ]))) // [ [ 1, 2 ], [ 2, 3 ] ] console.log(Array.from(mapAdjacent(pair, "hello"))) // [ [ h, e ], [ e, l ], [ l, l ], [ l, o ] ] console.log(Array.from(mapAdjacent(pair, [ 1 ]))) // [] console.log(Array.from(mapAdjacent(pair, []))) // []


0
投票
正如我在评论中提到的,我建议使用

reduce

。这是一个例子:

const input = [ {id: 1, value: "Apple Turnover"}, {id: 1, value: "Apple Turnover"}, {id: 2, value: "Banana Bread"}, {id: 3, value: "Chocolate"}, {id: 3, value: "Chocolate"}, {id: 3, value: "Chocolate"}, {id: 1, value: "Apple"}, {id: 4, value: "Danish"}, ]; // Desired output: Array of strings equal to values in the above array, // but with a prefix string of "New: " or "Repeated: " depending on whether // the id is repeated or not const reducer = (accumulator, currentValue) => { let previousValue, descriptions, isRepeatedFromPrevious; if (accumulator) { previousValue = accumulator.previousValue; descriptions = accumulator.descriptions; isRepeatedFromPrevious = previousValue.id === currentValue.id; } else { descriptions = []; isRepeatedFromPrevious = false; } if (isRepeatedFromPrevious) { // The following line is not purely functional and performs a mutation, // but maybe we do not care because the mutated object did not exist // before this reducer ran. descriptions.push("Repeated: " + currentValue.value); } else { // Again, this line is mutative descriptions.push("New: " + currentValue.value); } return { previousValue: currentValue, descriptions } }; const output = input.reduce(reducer, null).descriptions; document.getElementById('output').innerText = JSON.stringify(output);
<output id=output></output>


0
投票
您确定需要地图吗?这听起来像是一个

XY 问题。如果您想映射数组的相邻元素,那么您必须定义自己的函数。

const mapAdjacent = (mapping, array) => { const {length} = array, size = length - 1, result = new Array(size); for (let i = 0; i < size; i++) result[i] = mapping(array[i], array[i + 1]); return result; }; const items = [1, 2, 3, 4, 5]; const result = mapAdjacent((x, y) => [x, y], items); console.log(result); // [[1, 2], [2, 3], [3, 4], [4, 5]]

请注意,如果您给它一个空数组作为输入,这将抛出一个

RangeError

const mapAdjacent = (mapping, array) => { const {length} = array, size = length - 1, result = new Array(size); for (let i = 0; i < size; i++) result[i] = mapping(array[i], array[i + 1]); return result; }; const items = []; const result = mapAdjacent((x, y) => [x, y], items); // RangeError: Invalid array length console.log(result);

我认为这是一个很好的行为,因为你不应该一开始就给

mapAdjacent

 一个空数组。


这是

mapAdjacent

 的纯函数式实现,它使用 
reduceRight
。作为额外的好处,它适用于任何可迭代对象。

const mapAdjacent = (mapping, [head, ...tail]) => tail.reduceRight((recur, item) => prev => [mapping(prev, item), ...recur(item)] , _ => [])(head); const items = "hello"; const result = mapAdjacent((x, y) => [x, y], items); console.log(result); // [['h', 'e'], ['e', 'l'], ['l', 'l'], ['l', 'o']]

与迭代版本不同,如果您将空数组作为输入,它会返回一个空数组,而不是抛出错误。

const mapAdjacent = (mapping, [head, ...tail]) => tail.reduceRight((recur, item) => prev => [mapping(prev, item), ...recur(item)] , _ => [])(head); const items = ""; const result = mapAdjacent((x, y) => [x, y], items); console.log(result); // []

请注意,这是 JavaScript 中使用剩余元素进行数组解构的意外副作用。等效的 Haskell 版本确实会引发异常。

mapAdjacent :: (a -> a -> b) -> [a] -> [b] mapAdjacent f (x:xs) = foldr (\y g x -> f x y : g y) (const []) xs x main :: IO () main = do print $ mapAdjacent (,) "hello" -- [('h','e'),('e','l'),('l','l'),('l','o')] print $ mapAdjacent (,) "" -- Exception: Non-exhaustive patterns in function mapAdjacent

但是,此函数可能需要返回一个空数组。相当于在 Haskell 中添加

mapAdjacent f [] = []

 情况。


0
投票
我使用 F# 的

pairWise

 函数的实现:

function* pairWise(seq) { if (!seq?.length) return; let a = seq[0]; for (let i = 1; i < seq.length; i++) { const b = seq[i]; yield [a, b]; a = b; } }
用途:

[...pairWise([1, 2, 3, 4, 5])] // [[1, 2], [2, 3], [3, 4], [4, 5]] .map(([item1, item2], index) => null); [...pairWise('hi!')] // [['h, 'i'], ['i', '!']]
pairWise 本身并不是以纯函数方式实现的。也许可以,但我懒得打扰。

© www.soinside.com 2019 - 2024. All rights reserved.