我有一个名为
articles
的对象数组。一篇文章有 3 个重要的属性。 name
、clicks
和variants
。 variants
属性也是包含name
的对象数组(它对应于数组articles
中的一篇文章)。查找每篇文章点击次数最多的变体的最有效方法是什么?
我想也许有某种方法可以使用映射或扩展运算符,但我不明白语法。我想我可以创建一个“字典”,其中包含每组点击次数最多的文章,但是有更简单的方法吗?
输入:
[
{name: "article1",
clicks: 10,
variants: ["article2", "article3"]},
{name: "article2",
clicks: 7,
variants: ["article1", "article3"]},
{name: "article3",
clicks: 15,
variants: ["article1", "article2"]},
{name: "article4",
clicks: 3,
variants: ["article5"]},
{name: "article5",
clicks: 6,
variants: ["article4"]},
]
所需输出:
{name: "article1",
clicks: 10,
variants: ["article2", "article3"],
mostClickedVariant: "article3"}
{name: "article2",
clicks: 7,
variants: ["article1", "article3"],
mostClickedVariant: "article3"},
等等。每篇文章
试试这个(我在下面的代码片段中添加了所有描述性注释):
// Input array
const arr = [
{name: "article1",
clicks: 10,
variants: ["article2", "article3"]},
{name: "article2",
clicks: 7,
variants: ["article1", "article3"]},
{name: "article3",
clicks: 15,
variants: ["article1", "article2"]},
{name: "article4",
clicks: 3,
variants: ["article5"]},
{name: "article5",
clicks: 6,
variants: ["article4"]},
];
// Iterating over an input array.
const res = arr.map(obj => {
// Fetching variant objects in an array based on the variants name we have in the array.
const variantArr = obj.variants.map(variant => arr.find(o => o.name === variant));
// Getting most clicked variant object by sorting the variantArr in desc order based on the clicks.
const mostClickedVariant = variantArr.sort((a, b) => b.clicks - a.clicks)[0];
// creating a new property 'mostClickedVariant' in each obejct and assigning the name of the most clicked variant.
obj.mostClickedVariant = mostClickedVariant.name;
return obj;
});
// Expected output
console.log(res);
此版本不会改变原始版本,只是返回添加了新属性的副本。它还使用更有效的方法来查找最大值,在
O (n)
时间内将列表减少到最大值,而不是使用 O (n log n)
sort
。
const maxBy = (fn) => (xs) => xs .reduce (
({m, mx}, x, _, __, v = fn (x)) => v > m ? {m: v, mx: x} : {m, mx},
{m: -Infinity}
) .mx
const addMostClicked = (
articles,
index = new Map (articles .map (({name, clicks}) => [name, clicks])),
findMax = maxBy((x) => index .get (x))
) => articles .map (
(article) => ({... article, mostClickedVariant: findMax (article .variants)})
)
const articles = [{name: "article1", clicks: 10, variants: ["article2", "article3"]}, {name: "article2", clicks: 7, variants: ["article1", "article3"]}, {name: "article3", clicks: 15, variants: ["article1", "article2"]}, {name: "article4", clicks: 3, variants: ["article5"]}, {name: "article5", clicks: 6, variants: ["article4"]}]
console .log (addMostClicked (articles))
.as-console-wrapper {max-height: 100% !important; top: 0}
我们首先创建一个索引,将文章名称映射到其点击计数,然后使用帮助器
maxBy
,我们创建一个函数 findMax
,它将查找与最大点击计数相关的名称。
然后我们简单地映射元素,返回具有新
mostClickedVariant
属性的副本,通过使用变体名称列表调用 findMax
来确定。
根据您的期望:
import { TrueSet } from "@ut8pia/classifier/queue/TrueSet.js";
import { Classifier } from "@ut8pia/classifier/queue/Classifier.js";
import assert from "assert";
const
data = [
{name: "article1",
clicks: 10,
variants: ["article2", "article3"]},
{name: "article2",
clicks: 7,
variants: ["article1", "article3"]},
{name: "article3",
clicks: 15,
variants: ["article1", "article2"]},
{name: "article4",
clicks: 3,
variants: ["article5"]},
{name: "article5",
clicks: 6,
variants: ["article4"]},
],
expected = [
{name: "article1",
clicks: 10,
variants: ["article2", "article3"],
mostClickedVariant: "article3"},
{name: "article2",
clicks: 7,
variants: ["article1", "article3"],
mostClickedVariant: "article3"},
{name: "article3",
clicks: 15,
variants: ["article1", "article2"],
mostClickedVariant: "article1"},
{name: "article4",
clicks: 3,
variants: ["article5"],
mostClickedVariant: "article5"},
{name: "article5",
clicks: 6,
variants: ["article4"],
mostClickedVariant: "article4"},
]
但是,由于
mostClickedVariant
可以从您的数据中派生,因此建议使用函数而不是属性来定义它。这种方法可以防止数据冗余。
函数 sortedVariants(article)
可以灵活地返回所有变体,并按点击次数排序。
值得考虑为什么您对对每篇文章的变体进行排序感兴趣,但似乎对对整个文章集合进行排序不感兴趣。
此外,我建议区分数据集中的两种类型的信息:每篇文章的
clicks
和文章之间的 relationships
。识别和区分这些不同类型的信息是有益的。
const
clicks = new Classifier()
.letAll(data.map(obj => [obj.clicks, obj.name])),
relationships = new Classifier()
.letAll(data.map(obj => obj.variants
.map(variant => [obj.name, variant]))
.flat());
function sortedVariants(name) {
return new TrueSet(variant => clicks.class(undefined, variant).what()[0])
.letAll(relationships.class(name).then(entry => entry[1]))
}
文章按点击次数排序,文章之间的关系按字母顺序排序。方法
sortedVariants(name)
返回一个 TrueSet
,按升序表示每个变体的点击次数:
variant => clicks.class(undefined, variant).what()[0]
.
方法
what()
返回类的第一个也是唯一的条目 [clicks, article]
。因此,点击次数最多的变体是集合中的最后一个变体,可以通过 peek(false)
来检索。
您可以通过以下方式验证建议的解决方案:
assert.deepEqual(
data.map(obj => sortedVariants(obj.name).peek(false)),
expected.map(obj => obj.mostClickedVariant)
)