根据对象的键和值合并对象

时间:2020-02-13 15:14:38

标签: javascript arrays ecmascript-6 javascript-objects

我已经编辑了原始问题,因为该示例没有清楚地显示所需的输出,即我没有指定我需要与Rank

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

每个keys有三套object,我想每个集合只有一个实例,其最低编号为Rank,或者如果{{1} }在所有对象上均等于“-”。

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)

有什么想法吗?谢谢!

4 个答案:

答案 0 :(得分: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; }

答案 1 :(得分:2)

尝试这个

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

答案 2 :(得分:2)

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

在此代码段中,还有一个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);

答案 3 :(得分:0)

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

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)