Удалить повторяющиеся значения в объекте, но сохранить значение в массиве - PullRequest
0 голосов
/ 11 декабря 2018

Учитывая следующий массив объектов, как я могу создать новый, в котором, если есть объект с таким же адресом электронной почты, он просто добавляет favourSport в массив.Чего я хочу добиться - это удалить дубликаты данных.

Любые советы о том, как справиться с этим в Javascript?

data = [
  { 
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Soccer' 
  },
  { 
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Tennis' 
  },
  { 
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Swimming' 
  },
  { 
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Voleyball' 
  }
]

//Expected Output

[
  {
      name: 'Lisa Simpson',
      email: 'lisa@email.com',
      favoriteSport: ['Soccer', 'Tennis', 'Swimming', 'Voleyball']
  }
]

Ответы [ 5 ]

0 голосов
/ 12 декабря 2018

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

var app = (function() {
  var init = function() {
    combineDuplicateEntries(data);
  };

  data = [
      {
          name: 'Lisa Simpson',
          email: 'lisa@email.com',
          favoriteSport: 'Soccer'
        },
      {
          name: 'Lisa Simpson',
          email: 'lisa@email.com',
          favoriteSport: 'Tennis'
        },
      {
          name: 'Lisa Simpson',
          email: 'lisa@email.com',
          favoriteSport: 'Swimming'
        },
      {
          name: 'Lisa Simpson',
          email: 'lisa@email.com',
          favoriteSport: 'Voleyball'
        }

  ];

  var finalData = {};

  function combineDuplicateEntries(data) {
    if (Array.isArray(data)) {
      console.log('Data is an array.');
      findDulicates(data)
    }
  }

  function findDulicates(data) {
    var duplicate = false;

    data.map(function(item) {
      var emailProperty = item.email;
      var favoriteSport = item.favoriteSport;

      if (emailProperty in finalData) {

        if (!finalData[emailProperty].duplicate) {
          finalData[emailProperty].favoriteSports = [];
        }

        finalData[emailProperty].duplicate = true;
        finalData[emailProperty].favoriteSports.push(favoriteSport)

        if (finalData[emailProperty].favoriteSport) {
          finalData[emailProperty].favoriteSports.push(finalData[emailProperty].favoriteSport);
          delete finalData[emailProperty].favoriteSport
        }

        duplicate = true;
      } else {
        finalData[emailProperty] = item;
        delete item.duplicate;
      }

      return duplicate;
    });

    console.log("Final data: ", finalData);
  }

  return init();
});

app(); 
0 голосов
/ 12 декабря 2018

Вы можете сделать это, уменьшив массив до объекта, введенного по электронной почте, и соответствующих значений в качестве желаемых конечных объектов.Затем вы можете получить наш окончательный массив с Object.values:

var data = [{
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Soccer'
  },
  {
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Tennis'
  },
  {
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Swimming'
  },
  {
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Voleyball'
  },
  {
    name: 'Al Pacino',
    email: 'al@email.com',
    favoriteSport: 'Voleyball'
  }
];

var result = Object.values(data.reduce((acc, {favoriteSport, ...curr}) => {
  if (curr.email in acc) acc[curr.email].favoriteSport.push(favoriteSport);
  else acc[curr.email] = {...curr, favoriteSport: [favoriteSport]};
  return acc;
}, {}));

console.log(result);
0 голосов
/ 11 декабря 2018

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

const data = [{
        name: 'Lisa Simpson',
        email: 'lisa@email.com',
        favoriteSport: 'Soccer'
    },{
        name: 'Lisa Simpson',
        email: 'lisa@email.com',
        favoriteSport: 'Tennis'
    },{
        name: 'Lisa Simpson',
        email: 'lisa@email.com',
        favoriteSport: 'Swimming'
    },{
        name: 'Lisa Simpson',
        email: 'lisa@email.com',
        favoriteSport: 'Voleyball'}];

const group = (data) =>

    data.reduce((acc, val) => {

        const found = acc.find((item) => item.email === val.email);

        if (found && !found.favoriteSport.includes(val.favoriteSport)) found.favoriteSport.push(val.favoriteSport);

        else acc.push({ ...val, favoriteSport: [val.favoriteSport] });

        return acc;
    }, []);

console.log(group(data));

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

const data = [{
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Soccer'
},{
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Tennis'
},{
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Swimming'
},{
    name: 'Lisa Simpson',
    email: 'lisa@email.com',
    favoriteSport: 'Voleyball'}];

const group = (data) => {

    const result = data.reduce((acc, val) => {

        if (acc[val.email]) acc[val.email].favoriteSport[val.favoriteSport] = 1;

        else acc[val.email] = { ...val, favoriteSport: { [val.favoriteSport]: 1 } };

        return acc;
    }, {});

    Object.keys(result).forEach((key) => result[key].favoriteSport = Object.keys(result[key].favoriteSport));

    return Object.values(result);
};

console.log(group(data));
0 голосов
/ 11 декабря 2018

Предполагаемое решение должно быть доказательством общего подхода, основанного только на reduce.

Основная идея - написать функцию редуктора многократного использования, которая использует свой первый аргумент accumulator какобъект хранения, который содержит конфигурацию и результат этой конкретной задачи.Это также обогащает этот временно переданный объект как реестр, чтобы обеспечить быстрый поиск для лучшего обнаружения дубликатов элементов и строковых значений.

const data = [{
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Soccer'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Tennis'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Swimming'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Voleyball'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Soccer'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Tennis'
}, {
  name: 'Homer Simpson',
  email: 'homer@email.com',
  favoriteSport: 'Barbecuing'
}, {
  name: 'Homer Simpson',
  email: 'homer@email.com',
  favoriteSport: 'TV marathoning'
}];


function concatSameItemStringValueByKeys(collector, item) {
  const { assign } = Object;
  const { samenessKey, concatKey, list } = collector;

  const itemRegistry  = (collector.itemRegistry || (collector.itemRegistry = {}));

  const accessKey     = item[samenessKey];
  const stringValue   = item[concatKey];

  let registeredItem  = itemRegistry[accessKey];
  if (registeredItem) {

    if (!(stringValue in registeredItem.valueRegistry)) { // - prevent item specific value duplicates.
      registeredItem.valueRegistry[stringValue] = true;

      registeredItem.type[concatKey].push(stringValue);   // - concat item specific values.
    }
  } else {
    registeredItem = itemRegistry[accessKey] = {          // - create item specific registry.
      type: assign({}, item),                             // - assign shallow item copy.
      valueRegistry: {}                                   // - create item specific value registry.
    };
    registeredItem.valueRegistry[stringValue] = true;     // - prevent future item specific value duplicates.

    registeredItem.type[concatKey] = [stringValue];       // - map item specific value initially to {Array}.

    list.push(registeredItem.type); // - store the initially mapped+registered item additionally into a list.
  }
  return collector;
}

const reducedData = data.reduce(concatSameItemStringValueByKeys, {

  samenessKey: 'email',
  concatKey: 'favoriteSport',
  list: []

}).list;

console.log('reducedData : ', reducedData);
.as-console-wrapper { max-height: 100%!important; top: 0; }

Подобную проблему / задачу теперь можно решить с помощью того же редуктора и другой стартовой конфигурации ...

const data = [{
  id: 'xyz-abc',
  value: 'foo'
}, {
  id: 'xyz-abc',
  value: 'bar'
}, {
  id: 'ikl-mno',
  value: 'foo'
}, {
  id: 'ikl-mno',
  value: 'bar'
}, {
  id: 'xyz-abc',
  value: 'baz'
}, {
  id: 'xyz-abc',
  value: 'biz'
}, {
  id: 'ikl-mno',
  value: 'foo'
}, {
  id: 'ikl-mno',
  value: 'bar'
}, {
  id: 'xyz-abc',
  value: 'foo'
}, {
  id: 'xyz-abc',
  value: 'bar'
}];


function concatSameItemStringValueByKeys(collector, item) {
  const { assign } = Object;
  const { samenessKey, concatKey, list } = collector;

  const itemRegistry  = (collector.itemRegistry || (collector.itemRegistry = {}));

  const accessKey     = item[samenessKey];
  const stringValue   = item[concatKey];

  let registeredItem  = itemRegistry[accessKey];
  if (registeredItem) {

    if (!(stringValue in registeredItem.valueRegistry)) { // - prevent item specific value duplicates.
      registeredItem.valueRegistry[stringValue] = true;

      registeredItem.type[concatKey].push(stringValue);   // - concat item specific values.
    }
  } else {
    registeredItem = itemRegistry[accessKey] = {          // - create item specific registry.
      type: assign({}, item),                             // - assign shallow item copy.
      valueRegistry: {}                                   // - create item specific value registry.
    };
    registeredItem.valueRegistry[stringValue] = true;     // - prevent future item specific value duplicates.

    registeredItem.type[concatKey] = [stringValue];       // - map item specific value initially to {Array}.

    list.push(registeredItem.type); // - store the initially mapped+registered item additionally into a list.
  }
  return collector;
}

const reducedData = data.reduce(concatSameItemStringValueByKeys, {

  samenessKey: 'id',
  concatKey: 'value',
  list: []

}).list;

console.log('reducedData : ', reducedData);
.as-console-wrapper { max-height: 100%!important; top: 0; }
0 голосов
/ 11 декабря 2018

Вы можете выполнить итерацию с forEach, затем использовать find, filter и map для достижения ожидаемого результата.

Мы можем использовать new Set(array) для получения уникальных значений, а Array.from(new Set(array)) будетпреобразовать его снова в массив.

let a = [{
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Soccer'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Tennis'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Swimming'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Voleyball'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Soccer'
}, {
  name: 'Lisa Simpson',
  email: 'lisa@email.com',
  favoriteSport: 'Tennis'
}, {
  name: 'Homer Simpson',
  email: 'homer@email.com',
  favoriteSport: 'Barbecuing'
}, {
  name: 'Homer Simpson',
  email: 'homer@email.com',
  favoriteSport: 'TV marathoning'
}];

let result = [];
a.forEach((i) => {
  if (!result.find(x => x.name == i.name && x.email == i.email)) {
    result.push({
      name: i.name,
      email: i.email,
      favoriteSport: Array.from(new Set(a.filter(x => x.name == i.name && x.email == i.email).map(x => x.favoriteSport)))
    });
  }
});

console.log(result);
...