【问题标题】:javascrpt array group return undefined key valuejavascript数组组返回未定义的键值
【发布时间】:2021-05-07 15:05:11
【问题描述】:

我正在使用下面的代码有条件地向数组添加元素: 当 arr1 中的 domain 没有该域的 arr2 中的 kwd 时,添加键:域、键、位置:“n/a”、日期、引擎和设备。

jsfiddle

var arr1 = ["xxx", "yyy"];

var arr2 = [
  { domain: "xxx", kwd: "a", position: 1, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},
  { domain: "yyy", kwd: "a", position: 2, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},

  { domain: "xxx", kwd: "b", position: 1, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},
  { domain: "yyy", kwd: "b", position: 2, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},

  { domain: "yyy", kwd: "c", position: 2, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},

  { domain: "xxx", kwd: "d", position: 1, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"}
];

const grouped = arr2.reduce((group, entry) => {
  const lookup = group[entry.kwd] || {};
  return {
    ...group,
    [entry.kwd]: {
      ...lookup,
      [entry.domain]: entry
    }
  };
}, {});

const filledIn = Object.entries(grouped).reduce(
  (arr, [key, group]) => [
    ...arr,
    ...arr1.map((domain) =>
      domain in group
        ? group[domain]
        : {
            domain,
            kwd: key,
            position: "n/a",
            date: grouped.date,
            engine: grouped.engine,
            device:grouped.device,
          }
    )
  ],
  []
);

console.log(filledIn);

脚本运行良好,但返回未定义的日期、引擎和设备。

...
{
  date: undefined,
  device: undefined,
  domain: "yyy",
  engine: undefined,
  kwd: "d",
  position: "n/a"
}]

我该如何解决这个问题?

谢谢

【问题讨论】:

  • 运行你的 jsfiddle 表明只有一些条目没有日期和引擎。你试过调试你的代码吗?
  • 当您为 kwd:c 和 domain:xxx 定义 arr2 时,您缺少 kwd:d 和 domain:yyy 的对象
  • 您的目标是返回“n/a”而不是 undefined

标签: javascript jquery arrays


【解决方案1】:

这是修改后的代码,用于在我的original answer 中填充缺失域的更多值。我还添加了一些 cmets。

编辑:通过在最后一步中使用flatMap(),而不是使用reduce() 手动生成平面数组,我能够使代码更加简单。

// Group all array rows by their keyword, and inside of the group index each
// entry by its domain, so we can easily check if a domain is in this group.
// Also store an an example of a known good entry so we can clone its values
// onto missing entries in the next step
const grouped = arr2.reduce(
  (groups, entry) => ({
    ...groups,
    [entry.kwd]: {
      ...(groups[entry.kwd] || {}),
      example: entry,
      [entry.domain]: entry
    }
  }),
  {}
);

// Now iterate over the group and pull out all the valid known domains and put
// it back into array form. If a domain is missing, use the "example" we
// captured get example values of a valid domain, and fill in the rest manually
const filledIn = Object.values(grouped).flatMap((group) =>
  arr1.map(
    (domain) =>
      group[domain] || {
        ...group.example,
        position: "n/a"
      }
  )
);

console.log(filledIn);

【讨论】:

    【解决方案2】:

    我已经完成了您正在做的事情,但代码更简单。看看是不是你想要的。

    在示例中,最终日志将相同的字母对象组合在一起,您可以使用...进行更改

    const arr1 = ["xxx", "yyy"];
    
    const arr2 = [{
        domain: "xxx",
        kwd: "a",
        position: 1,
        date: "2021-05-07T08:05:16.806Z",
        engine: "google",
        device: "desktop"
      },
      {
        domain: "yyy",
        kwd: "a",
        position: 2,
        date: "2021-05-07T08:05:16.806Z",
        engine: "google",
        device: "desktop"
      },
    
      {
        domain: "xxx",
        kwd: "b",
        position: 1,
        date: "2021-05-07T08:05:16.806Z",
        engine: "google",
        device: "desktop"
      },
      {
        domain: "yyy",
        kwd: "b",
        position: 2,
        date: "2021-05-07T08:05:16.806Z",
        engine: "google",
        device: "desktop"
      },
    
      {
        domain: "yyy",
        kwd: "c",
        position: 2,
        date: "2021-05-07T08:05:16.806Z",
        engine: "google",
        device: "desktop"
      },
    
      {
        domain: "xxx",
        kwd: "d",
        position: 1,
        date: "2021-05-07T08:05:16.806Z",
        engine: "google",
        device: "desktop"
      }
    ];
    
    // making a new array with all the kwd options.
    // use Set() for unique items in array, so no duplicates.
    const letters = [...new Set(arr2.map(elm => elm.kwd))];
    
    // looping through letters
    const filled = letters.map(letter => {
    
      // looping through domains
      return arr1.map((domain, i) => {
    
        // if the domain and letter combination already exists, make a copy of the object and return it.
        if (arr2.some(obj => obj.domain == domain && obj.kwd == letter)) {
          const copy = arr2.find((elm) => elm.kwd === letter && elm.domain === domain);
          return Object.assign({}, copy);
        }
    
        // if there are no copies, copy the other domain with the same letter and change the domain and position.
        let copy = arr2.find(({
          kwd
        }) => kwd === letter);
        copy.domain = domain;
        copy.position = i + 1;
        return Object.assign({}, copy);
      });
    });
    
    
    console.log(filled);

    【讨论】:

    • 当我处理此类问题时,我会考虑解析一种有用的中间格式,如果它有助于解决问题。进行初始分组让我可以进行简单的in 检查以验证是否存在值。否则,您必须处理初始数据结构的限制,也就是在这里使用 .some().find() 两次,您必须编写搜索逻辑。对于这么小的数据集,这些嵌套循环的效率可能并不重要。像您在这里所做的那样混合解析和解决问题是可行的,对我个人而言,单独的步骤更容易推理
    • 是的,许多嵌套循环可能非常慢,尤其是 map 和 forEach,我只是使用它们,因为它更容易查看数据发生了什么。您的版本更适合生产,但对于新程序员来说很难遵循。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 2022-11-25
    相关资源
    最近更新 更多