【问题标题】:Merge objects according to their keys and values根据对象的键和值合并对象
【发布时间】:2020-02-13 15:14:38
【问题描述】:

我已经编辑了原始问题,因为示例没有明确所需的输出,即我没有指定我需要与 Rank 匹配的对象共有的字符串

我正在尝试将一组对象合并为一个对象

每个object 有三组keys,我希望每组只有一个实例,其中Rank 值的编号最小,或者如果Rank 在所有对象上等于'-' .

let objs = [
  {
    Keyword: 'A keyword',
    'First Rank': '-',
    'First Title': '-',
    'First URL': '-',
    'Second Rank': '-',
    'Second Title': '-',
    'Second URL': '-',
    'Third Rank': 1,
    'Third Title': 'Title for 1',
    'Third URL': 'https://for-one.example.com'
  },
  {
    Keyword: 'A keyword',
    'First Rank': '-',
    'First Title': '-',
    'First URL': '-',
    'Second Rank': 2,
    'Second Title': 'Title for 2',
    'Second URL': 'https://for-two.example.com',
    'Third Rank': '-',
    'Third Title': '-',
    'Third URL': '-'
  },
  {
    Keyword: 'A keyword',
    'First Rank': '-',
    'First Title': '-',
    'First URL': '-',
    'Second Rank': '-',
    'Second Title': '-',
    'Second URL': '-',
    'Third Rank': 7,
    'Third Title': 'Title for 7',
    'Third URL': 'https://for-seven.example.com'
  }
]

// I have managed to get the ones with values with this:


const clean = objs.reduce((acc, object) => {
  const clone = (({ Keyword, ...obj }) => obj)(object)

  if (Object.values(clone).some(val => val !== '-')) {
    Object.keys(clone).forEach(key => object[key] === '-' && delete object[key])
    acc.push(object)
  }

  return acc
}, [])

const merged = clean.reduce((result, current) => ({ ...current, ...result }), {})

console.log(merged)

但我正在努力添加一个没有值的,它应该是这样的:

{
  'Keyword': 'A keyword',
  'First Rank': '-',
  'First Title': '-',
  'First URL': '-',
  'Second Rank': 2,
  'Second Title': 'Title for 2',
  'Second URL': 'https://for-two.example.com',
  'Third Rank': 1,
  'Third Title': 'Title for 1',
  'Third URL': 'https://for-one.example.com'
}

有什么想法吗?谢谢!

【问题讨论】:

    标签: javascript arrays ecmascript-6 javascript-objects


    【解决方案1】:

    试试这个

    let objs = [
      {
        'Keyword': 'A keyword',
        'First URL': '-',
        'First Rank': '-',
        'First Title': '-',
        'Second URL': '-',
        'Second Rank': '-',
        'Second Title': '-',
        'Third URL': '-',
        'Third Rank': '-',
        'Third Title': '-'
      },
      {
        'Keyword': 'A keyword',
        'First URL': '-',
        'First Rank': '-',
        'First Title': '-',
        'Second URL': '-',
        'Second Rank': '-',
        'Second Title': '-',
        'Third URL': 'https://example.com',
        'Third Rank': 7,
        'Third Title': 'Title'
      },
      {
        'Keyword': 'A keyword',
        'First URL': '-',
        'First Rank': '-',
        'First Title': '-',
        'Second URL': 'https://example.com',
        'Second Rank': 11,
        'Second Title': 'Title',
        'Third URL': '-',
        'Third Rank': '-',
        'Third Title': '-'
      },
      {
        'Keyword': 'A keyword',
        'First URL': '-',
        'First Rank': '-',
        'First Title': '-',
        'Second URL': '-',
        'Second Rank': '-',
        'Second Title': '-',
        'Third URL': 'https://example.com',
        'Third Rank': 1,
        'Third Title': 'Title overwritten'
      },
    ]
    
    
    var result = objs.slice().reduce((acc, item, index) => {
      resultItem = acc.find(accItem => accItem['Keyword'] === item['Keyword']);
      if (!resultItem) {
        acc.push(item)
      } else {
        Object.keys(resultItem).map(k => {
          if (item[k] !== '-') {
            if (typeof item[k] === 'number') {
              resultItem[k] = resultItem[k] === '-' ? item[k] : Math.min(item[k], resultItem[k]);
            } else {
              resultItem[k] = item[k];
            }
          }
        })
      }
      return acc;  
    }, []);
    
    console.log(result);

    【讨论】:

    • 谢谢,但仍然没有取最低的Rank 值,如果我们在Second Rank 集合上添加另一个具有较低等级值的对象,比如说1,它仍然会取11 的对象跨度>
    • 好的,我会更新它。应该如何处理字符串?它应该采取第一个还是最后一个或什么?
    • 我正在更新问题,字符串应该被忽略它只是重要的Rank
    • 我还更新了答案,在Third Title 抢夺。在我的示例中,它应该如何表现,应该第三个标题是“标题覆盖”还是只是“标题”?
    • 其实我觉得我弄错了,字符串确实很重要,它必须与属于Rank的对象相关 我做了一些测试,我可以看到我得到了排名从最小的数字,但另一个对象的标题
    【解决方案2】:

    您可以减少并在处理程序中检查数字值,以便比较两个值之间的最小值。

    在这段代码 sn-p 中有一个带有Third Rank = 1的附加对象

    let array = [{ Keyword: 'A keyword', 'First URL': '-', 'First Rank': '-', 'First Title': '-', 'Second URL': '-', 'Second Rank': '-', 'Second Title': '-', 'Third URL': '-', 'Third Rank': '-', 'Third Title': '-' }, { Keyword: 'A keyword', 'First URL': '-', 'First Rank': '-', 'First Title': '-', 'Second URL': '-', 'Second Rank': '-', 'Second Title': '-', 'Third URL': 'https://example.com', 'Third Rank': 7, 'Third Title': '2 third title' }, { Keyword: 'A keyword', 'First URL': '-', 'First Rank': '-', 'First Title': '-', 'Second URL': 'https://example.com', 'Second Rank': 11, 'Second Title': '3 Second title', 'Third URL': '-', 'Third Rank': '-', 'Third Title': '-' }, { Keyword: 'A keyword', 'First URL': '-', 'First Rank': '-', 'First Title': '-', 'Second URL': 'https://example.com', 'Second Rank': 11, 'Second Title': '3 Second title', 'Third URL': '-', 'Third Rank': 1, 'Third Title': '-' }],
        merged = array.reduce(({ ...r }, o) => {
            Object.entries(o).forEach(([k, v]) => {
                if (v !== '-') {
                  if (isNaN(+v) || isNaN(+r[k])) r[k] = v;
                  else r[k] = Math.min(+r[k], +v);
                }
            });
            return r;
        });
        
    console.log(merged);

    【讨论】:

    • @Álvaro yw (:
    • 对不起,我在示例中犯了一个错误,最终对象必须具有属于该选定对象的 Rank TitleURL,我从 @ 获得最小的数字987654327@ 但来自另一个对象的 URL 和标题
    【解决方案3】:

    您可以减少数组并检查条目的键。

    let array = [{ 'Keyword': 'A keyword', 'First URL': '-', 'First Rank': '-', 'First Title': '-', 'Second URL': '-', 'Second Rank': '-', 'Second Title': '-', 'Third URL': '-', 'Third Rank': '-', 'Third Title': '-' }, { 'Keyword': 'A keyword', 'First URL': '-', 'First Rank': '-', 'First Title': '-', 'Second URL': '-', 'Second Rank': '-', 'Second Title': '-', 'Third URL': 'https://for-seven.example.com', 'Third Rank': 7, 'Third Title': 'Title' }, { 'Keyword': 'A keyword', 'First URL': '-', 'First Rank': '-', 'First Title': '-', 'Second URL': 'https://for-eleven.example.com', 'Second Rank': 11, 'Second Title': 'Title', 'Third URL': '-', 'Third Rank': '-', 'Third Title': '-' }, { 'Keyword': 'A keyword', 'First URL': '-', 'First Rank': '-', 'First Title': '-', 'Second URL': '-', 'Second Rank': '-', 'Second Title': '-', 'Third URL': 'https://for-one.example.com', 'Third Rank': 1, 'Third Title': 'Title' }],
        merged = array.reduce(({ ...r }, o) => {
            var prefix = ['First', 'Second', 'Third'].find(k => o[k + ' Rank'] !== '-'),
                rank = prefix + ' Rank';
    
            if (r[rank] < o[rank]) return;
            ['URL', 'Rank', 'Title'].forEach(k => {
                var key = `${prefix} ${k}`
                r[key] = o[key];
            });
            return r;
        });
        
    console.log(merged);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 但这并不能重现所需的输出,我也需要First 的键集,其值为'-'
    • 这个{ ...r }的目的是什么?
    • 避免突变?
    • @Nina Scholz 现在它可以工作,但它不会采用最低 Rank Value 它采用最高,如果我添加另一个 obj 并将 Third Rank 值设置为 1 它仍然采用 7
    • 什么是最低和最高?同一组第一/第二/第三的值?一个对象中只有一个组吗?
    【解决方案4】:

    感谢所有回答这个问题的人,但是我没有详细解释一些要求,当我这样做时已经来不及得到后续答复,所以我自己做了,我相信有更好的方法做吧,但这行得通。

    let objs = [
      {
        'Keyword': 'A keyword',
        'First Rank': '-',
        'First Title': '-',
        'First URL': '-',
        'Second Rank': '-',
        'Second Title': '-',
        'Second URL': '-',
        'Third Rank': 1,
        'Third Title': 'Title for 1',
        'Third URL': 'https://for-one.example.com'
      },
      {
        'Keyword': 'A keyword',
        'First Rank': '-',
        'First Title': '-',
        'First URL': '-',
        'Second Rank': 2,
        'Second Title': 'Title for 2',
        'Second URL': 'https://for-two.example.com',
        'Third Rank': '-',
        'Third Title': '-',
        'Third URL': '-'
      },
      {
        'Keyword': 'A keyword',
        'First Rank': '-',
        'First Title': '-',
        'First URL': '-',
        'Second Rank': '-',
        'Second Title': '-',
        'Second URL': '-',
        'Third Rank': 7,
        'Third Title': 'Title for 7',
        'Third URL': 'https://for-seven.example.com'
      }
    ]
    
    // Remove dashed entries and keep only the ones with data
    const removeDashed = objs.reduce((acc, object) => {
      // Clone object except for the keyword key
      const clone = (({ Keyword, ...obj }) => obj)(object)
      if (Object.values(clone).some(val => val !== '-')) {
        Object.keys(object).forEach(key => object[key] === '-' && delete object[key])
        acc.push(object)
      }
      return acc
    }, [])
    
    // Merge array into a single object with first entries found first
    const merged = removeDashed.reduce((result, current) => ({ ...current, ...result }), {})
    
    // Items that should be present
    const items = ['First', 'Second', 'Third']
    
    // Get the existing keys from the unique obj
    const keys = Object.keys(merged).map(key => key.split(' ')[0])
    
    // If one or more items are missing insert them and add dashed values
    items.forEach(item => {
      if (!keys.includes(item)) {
        merged[`${item} Rank`] = '-'
        merged[`${item} Title`] = '-'
        merged[`${item} URL`] = '-'
      }
    })
    
    // Sort function to reorder | thanks to Soc for this
    const sorting = item => (a, b) => {
      const alphaOrder = a < b ? -1 : a > b ? 1 : 0
    
      if (a === 'Keyword') return -1
      if (b === 'Keyword') return 1
      if (a.startsWith(item) && b.startsWith(item)) return alphaOrder
      if (a.startsWith(item)) return -1
      if (b.startsWith(item)) return 1
    
      return alphaOrder
    }
    
    // Implement the sorting
    const result = Object.keys(merged)
      .sort(sorting(items[0]))
      .reduce((acc, current) => {
        acc[current] = merged[current]
        return acc
      }, {})
    
    console.log(result)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-21
      • 1970-01-01
      • 2022-12-15
      • 1970-01-01
      • 2021-04-12
      • 2021-07-25
      相关资源
      最近更新 更多