gpt4 book ai didi

functional-programming - 在对象嵌套数组中查找对象的路径

转载 作者:行者123 更新时间:2023-12-04 00:18:11 25 4
gpt4 key购买 nike

我有一个对象,其参数包含对象数组。我收到 1 个对象 ID,我需要在整个困惑中找到它的位置。通过过程式编程,我可以使用它:

const opportunitiesById =  {
1: [
{ id: 1, name: 'offer 1' },
{ id: 2, name: 'offer 1' }
],
2: [
{ id: 3, name: 'offer 1' },
{ id: 4, name: 'offer 1' }
],
3: [
{ id: 5, name: 'offer 1' },
{ id: 6, name: 'offer 1' }
]
};

const findObjectIdByOfferId = (offerId) => {
let opportunityId;
let offerPosition;
const opportunities = Object.keys(opportunitiesById);

opportunities.forEach(opportunity => {
const offers = opportunitiesById[opportunity];

offers.forEach((offer, index) => {
if (offer.id === offerId) {
opportunityId = Number(opportunity);
offerPosition = index;
}
})
});

return { offerPosition, opportunityId };
}

console.log(findObjectIdByOfferId(6)); // returns { offerPosition: 1, opportunityId: 3 }

但是这并不漂亮,我想以一种实用的方式来做到这一点。我查看了 Ramda,当我查看单个报价数组时可以找到报价,但我找不到查看整个对象的方法 => 每个数组都可以找到我报价的路径.

R.findIndex(R.propEq('id', offerId))(opportunitiesById[1]);

我需要知道路径的原因是因为我需要用新数据修改该报价并将其更新回原处。

感谢您的帮助

最佳答案

可以使用许多小函数将其组合在一起,但我想向您展示如何以更直接的方式对您的意图进行编码。这个程序有一个额外的好处,它会立即返回。也就是说,在找到匹配项后,它不会继续搜索其他键/值对。

这里有一种使用相互递归的方法。首先我们写 findPath -

const identity = x =>
x

const findPath =
( f = identity
, o = {}
, path = []
) =>
Object (o) === o
? f (o) === true
? path
: findPath1 (f, Object .entries (o), path)
: undefined

如果输入是一个对象,我们将它传递给用户的搜索函数f。如果用户的搜索函数返回 true,则表示已找到匹配项,我们将返回 path。如果不匹配,我们使用辅助函数搜索对象的每个键/值对。否则,如果输入不是一个对象,则没有匹配项,也没有任何东西可供搜索,因此返回undefined。我们编写助手,findPath1 -

const None =
Symbol ()

const findPath1 =
( f = identity
, [ [ k, v ] = [ None, None ], ...more ]
, path = []
) =>
k === None
? undefined
: findPath (f, v, [ ...path, k ])
|| findPath1 (f, more, path)

如果键/值对已用尽,则没有任何内容可供搜索,因此返回 undefined。否则我们有一个键 k 和一个值 v;将 k 附加到路径并递归搜索 v 以进行匹配。如果没有匹配项,则使用相同的 path 递归搜索剩余的键/值 more

请注意每个函数的简单性。除了将 path 组装到匹配对象的绝对最少步骤外,没有任何事情发生。你可以像这样使用它 -

const opportunitiesById = 
{ 1:
[ { id: 1, name: 'offer 1' }
, { id: 2, name: 'offer 1' }
]
, 2:
[ { id: 3, name: 'offer 1' }
, { id: 4, name: 'offer 1' }
]
, 3:
[ { id: 5, name: 'offer 1' }
, { id: 6, name: 'offer 1' }
]
}

findPath (offer => offer.id === 6, opportunitiesById)
// [ '3', '1' ]

返回的路径将我们引向我们想要查找的对象 -

opportunitiesById['3']['1']
// { id: 6, name: 'offer 1' }

我们可以专门化 findPath 来制作一个直观的 findByOfferId 函数 -

const findByOfferId = (q = 0, data = {}) =>
findPath (o => o.id === q, data)

findByOfferId (3, opportunitiesById)
// [ '2', '0' ]

opportunitiesById['2']['0']
// { id: 3, name: 'offer 1' }

Array.prototype.find 一样,如果从未找到匹配,它返回 undefined -

findByOfferId (99, opportunitiesById)
// undefined

展开下面的代码片段以在您自己的浏览器中验证结果 -

const identity = x =>
x

const None =
Symbol ()

const findPath1 =
( f = identity
, [ [ k, v ] = [ None, None ], ...more ]
, path = []
) =>
k === None
? undefined
: findPath (f, v, [ ...path, k ])
|| findPath1 (f, more, path)

const findPath =
( f = identity
, o = {}
, path = []
) =>
Object (o) === o
? f (o) === true
? path
: findPath1 (f, Object .entries (o), path)
: undefined

const findByOfferId = (q = 0, data = {}) =>
findPath (o => o.id === q, data)

const opportunitiesById =
{ 1:
[ { id: 1, name: 'offer 1' }
, { id: 2, name: 'offer 1' }
]
, 2:
[ { id: 3, name: 'offer 1' }
, { id: 4, name: 'offer 1' }
]
, 3:
[ { id: 5, name: 'offer 1' }
, { id: 6, name: 'offer 1' }
]
}

console .log (findByOfferId (3, opportunitiesById))
// [ '2', '0' ]

console .log (opportunitiesById['2']['0'])
// { id: 3, name: 'offer 1' }

console .log (findByOfferId (99, opportunitiesById))
// undefined


在此related Q&A ,我演示了一个递归搜索函数,它返回匹配的对象,而不是匹配的路径。还有其他有用的花絮,因此我建议您看一下。


Scott 的回答启发了我尝试使用生成器实现。我们从 findPathGen -

开始
const identity = x =>
x

const findPathGen = function*
( f = identity
, o = {}
, path = []
)
{ if (Object (o) === o)
if (f (o) === true)
yield path
else
yield* findPathGen1 (f, Object .entries (o), path)
}

并且像我们上次那样使用相互递归,我们调用 helper findPathGen1 -

const findPathGen1 = function*
( f = identity
, entries = []
, path = []
)
{ for (const [ k, v ] of entries)
yield* findPathGen (f, v, [ ...path, k ])
}

最后,我们可以实现findPath 和特化findByOfferId -

const first = ([ a ] = []) =>
a

const findPath = (f = identity, o = {}) =>
first (findPathGen (f, o))

const findByOfferId = (q = 0, data = {}) =>
findPath (o => o.id === q, data)

它的工作原理是一样的-

findPath (offer => offer.id === 3, opportunitiesById)
// [ '2', '0' ]

findPath (offer => offer.id === 99, opportunitiesById)
// undefined

findByOfferId (3, opportunitiesById)
// [ '2', '0' ]

findByOfferId (99, opportunitiesById)
// undefined

作为奖励,我们可以使用 Array.from 轻松实现 findAllPaths -

const findAllPaths = (f = identity, o = {}) =>
Array .from (findPathGen (f, o))

findAllPaths (o => o.id === 3 || o.id === 6, opportunitiesById)
// [ [ '2', '0' ], [ '3', '1' ] ]

通过展开下面的代码片段来验证结果

const identity = x =>
x

const findPathGen = function*
( f = identity
, o = {}
, path = []
)
{ if (Object (o) === o)
if (f (o) === true)
yield path
else
yield* findPathGen1 (f, Object .entries (o), path)
}

const findPathGen1 = function*
( f = identity
, entries = []
, path = []
)
{ for (const [ k, v ] of entries)
yield* findPathGen (f, v, [ ...path, k ])
}

const first = ([ a ] = []) =>
a

const findPath = (f = identity, o = {}) =>
first (findPathGen (f, o))


const findByOfferId = (q = 0, data = {}) =>
findPath (o => o.id === q, data)

const opportunitiesById =
{ 1:
[ { id: 1, name: 'offer 1' }
, { id: 2, name: 'offer 1' }
]
, 2:
[ { id: 3, name: 'offer 1' }
, { id: 4, name: 'offer 1' }
]
, 3:
[ { id: 5, name: 'offer 1' }
, { id: 6, name: 'offer 1' }
]
}

console .log (findByOfferId (3, opportunitiesById))
// [ '2', '0' ]

console .log (findByOfferId (99, opportunitiesById))
// undefined

// --------------------------------------------------
const findAllPaths = (f = identity, o = {}) =>
Array .from (findPathGen (f, o))

console .log (findAllPaths (o => o.id === 3 || o.id === 6, opportunitiesById))
// [ [ '2', '0' ], [ '3', '1' ] ]

关于functional-programming - 在对象嵌套数组中查找对象的路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56066101/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com