在 Javascript 中给定嵌套的变体数组,在对象数组中查找“点击次数最多”的变体

问题描述 投票:0回答:3

我有一个名为

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"},

等等。每篇文章

javascript arrays recursion nested circular-reference
3个回答
0
投票

试试这个(我在下面的代码片段中添加了所有描述性注释)

// 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);


0
投票

此版本不会改变原始版本,只是返回添加了新属性的副本。它还使用更有效的方法来查找最大值,在

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
来确定。


0
投票

根据您的期望:

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)
)
© www.soinside.com 2019 - 2024. All rights reserved.