2

tl;dr

Im trying to deduplicate an array of objects that are not necessarily identical.

desc.

i have downloaded a set of records from a site that manages them poorly and there are many duplicates of records, though some with different names or different weights. What id like to do is compare each record to each other record and remove all entries but the one with the greatest weight, or all but one entry in the case that there is an exact duplicate (including name).

Arr obj

{
      "entry"   : "Single Lift",
      "name"    : "Jane Doe",
      "sex"     : "female",
      "division": "40-44",
      "equipped": "raw",
      "wtclass" : 66,
      "lift"    : "bench press",
      "weight"  : 151
  }

Pseudo

function dedupe(lift=records){
    console.log(lift.length)
    lift.forEach((record,index)=>{
      for(i=0;i<lift.length;i++){
        if(record.sex===lift[i].sex){
          if(record.division===lift[i].division){
            if(record.equipped===lift[i].equipped){
              if(record.wtclass===lift[i].wtclass){
                if(record.entry===lift[i].entry){
                  if(record.name===lift[i].name&&record.weight===lift[i].weight) lift.splice(i,1)
                  else if(record.weight>lift[i].weight) lift.splice(i,1)
                  else if(record.weight<lift[i].weight) lift.splice(index,1)
                }
              }
            }
          }
        }
      }
    })
    console.log(lift.length)
    return lift
  }

This code obviously doesn't operate the way i want it to, but it illustrates the intent. I would like to remove all but the greatest weight (or all but one where all key:values are identical) by comparing the weight on any entry where entry sex division equipped wtclass and lift are a match.

There are other questions around about deduplicating arrays of objects, but i could not find anything that matched my scenario or that i could adapt to work for me. If anyone has a solution (or a link to a solution) i would greatly appreciate it!

7
  • 3
    Best you can do is declare an empty array. Then loop over the data you have and push the objects if they are not already present in the empty array. If they are present, check if the weight is bigger and replace it. And so on. Forget this IF hell you wrote Commented Mar 8, 2018 at 18:49
  • I'm a little unclear, are you saying you want to find all the personal bests for each duplicate of 'everything but weight'? Because yBrodsky's comment would be correct if so. Commented Mar 8, 2018 at 19:05
  • My issue is that some lifts have been entered twice as exact duplicates (not hard to deal with) but also when a record was broken, sometimes the old record was not removed, so there will be two of the same record with different weight values. I only want to keep a given record with the greatest weight. I am working on a new function based on yBrodsky's suggestion now, but am also interested in the reduce option answered below, though im unfamiliar with reduce Commented Mar 8, 2018 at 19:16
  • 1
    A quick copy paste of Ele's code definitely gets it done, though i dont understand what its doing very well. Thats fine by me though, t least i have something that works, and can start googling to understand what im seeing! thanks for the help everyone! Commented Mar 8, 2018 at 19:43
  • 1
    @Ele ...wow. That's actually more beautiful, too! Commented Mar 8, 2018 at 19:48

3 Answers 3

3

With those values you can concatenate them and check for the duplicates.

You can use the function reduce.

This example has two objects with the same values (but the weights) and one of them with different values.

var array = [
  {
    'entry': 'Single Lift',
    'name': 'Jane Doe',
    'g': 'f',
    'division': '40-44',
    'equipped': 'raw',
    'wtclass': 66,
    'lift':
    'bench press', 'weight': 151
  },
  {
    'entry': 'Single Lift',
    'name': 'Jane Doe',
    'g': 'f',
    'division': '40-44',
    'equipped': 'raw',
    'wtclass': 66,
    'lift': 'bench press',
    'weight': 160
  },
  {
    'entry': 'Single Lift', 
    'name': 'Ele', 
    'g': 'm', 
    'division': '40-44', 
    'equipped': 'raw', 
    'wtclass': 66, 
    'lift': 'bench press', 
    'weight': 151
  }
]

var result = Object.values(array.reduce((a, o) => {
  var {
    entry, 
    name, 
    g, 
    division, 
    equipped, 
    wtclass, lift
  } = o
  
  var key = [
    entry, 
    name, 
    g, 
    division, 
    equipped, 
    wtclass, 
    lift
  ].join('||')

  if (!a[key] || o.weight > a[key].weight) {
    a[key] = o
  }

  return a
}, {}))

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

Sign up to request clarification or add additional context in comments.

Comments

0

const array = [
  { "entry"   : "Single Lift", "name"    : "Jane Doe", "sex"     : "female", "division": "40-44", "equipped": "raw", "wtclass" : 66, "lift"    : "bench press", "weight"  : 151 }, { "entry"   : "Single Lift", "name"    : "Jane Doe", "sex"     : "female", "division": "40-44", "equipped": "raw", "wtclass" : 66, "lift"    : "bench press", "weight"  : 152 }, { "entry"   : "Single Lift", "name"    : "Jane Doe", "sex"     : "female", "division": "40-44", "equipped": "raw", "wtclass" : 66, "lift"    : "bench press", "weight"  : 151 }, { "entry"   : "Double Lift", "name"    : "Jane Doe", "sex"     : "female", "division": "40-44", "equipped": "raw", "wtclass" : 66, "lift"    : "bench press", "weight"  : 151 }
]

const groupBy = (xs, exceptions) => 
   xs.reduce((groups, element) => {
     var key = Object.assign({}, element);
     for (let i = 0; i < exceptions.length; i++) {
       delete key[exceptions[i]];
     }
     key = Object.values(key).join(',');
           
     if (!groups[key]) {
        groups[key] = [element];
     } else {
        groups[key].push(element);
     }

     return groups;
   }, {})

let grouppedRecords = groupBy(array, ['weight']);

let biggestWeightRecords = Object.values(grouppedRecords).map(records => {
  let biggestWeightRecord = records[0];
  for (let i = 0; i < records.length; i++) {
    if (records[i].weight > biggestWeightRecord.weight) {
      biggestWeightRecord = records[i];
    }
  }
  return biggestWeightRecord;
});

console.log(biggestWeightRecords);

Comments

0

Solution with 2 iterations, admit any number of properties to filter by, two rules (bigger and smaller), just works if the values of filter properties are primitive values.

const elements = [
    {
        foo: 1,
        bar: 2,
        fooBard: 3,
    },
    {
        foo: 2,
        bar: 2,
        fooBard: 6,
    },
    {
        foo: 1,
        bar: 2,
        fooBard: 5,
    },
    {
        foo: 2,
        bar: 2,
        fooBard: 3,
    }
];

const RULE_BIGGER = 'RULE_BIGGER';
const RULE_SMALLER = 'RULE_SMALLER';

const elementsFiltered = new Map();

const createKey = (element, ...matchingProperties) =>
    matchingProperties
    .map(matchProperty => element[matchProperty] || '')
    .join('#');


const hasToBeUpdated = (rule) => (oldValue, newValue) => {
    switch (rule) {
        case RULE_BIGGER:
            return newValue > oldValue;
        case RULE_SMALLER:
            return newValue < oldValue;
        default:
            return false;
    }
}

const filterByProperty = (elements, property, rule, ...matchingProperties) => {
    const hasToBeUpdatedWithRule = hasToBeUpdated(rule);
    elements.forEach((element) => {
        const key = createKey(element, ...matchingProperties);
        const storedElement = elementsFiltered.get(key)
        if (!storedElement ||
            hasToBeUpdatedWithRule(storedElement[property], element[property])) {
                elementsFiltered.set(key, element);
        }
    });
    const result = [];
    elementsFiltered.forEach(elementFiltered => {
        result.push(elementFiltered);
    });
    return result;
};

const result = filterByProperty(elements, 'fooBard', RULE_BIGGER, 'foo', 'bar');

console.log(result);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.