Объединять объекты в соответствии с их ключами и значениями - PullRequest
1 голос
/ 13 февраля 2020

Я отредактировал исходный вопрос, так как пример не дал желаемого результата, а именно я не указал, что мне нужны строки, общие с объектом, который соответствует Rank

Я пытаюсь объединить массив объектов в один объект

Есть три набора keys на object, я хотел бы иметь только один экземпляр каждого набора с самым низким число для значения 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'
}

Есть идеи? Спасибо!

Ответы [ 4 ]

3 голосов
/ 13 февраля 2020

Вы можете уменьшить массив и проверить ключ записей.

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; }
2 голосов
/ 13 февраля 2020

Вы можете уменьшить и в пределах обработчика проверить числовое значение, чтобы сравнить, какое из двух значений является наименьшим.

В этом фрагменте кода есть дополнительный объект с 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);
2 голосов
/ 13 февраля 2020

Попробуйте это

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);
0 голосов
/ 14 февраля 2020

Спасибо всем, кто ответил на этот вопрос, однако я не объяснил подробно некоторые требования, и когда я сделал это, было слишком поздно, чтобы получить ответ о последующей деятельности, поэтому я сделал свой собственный, я уверен, что есть лучший способ сделай это, но это работает.

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