0

I am fetching data from an api that, sometimes, gives me multiple objects with the same values, or very similar values, which I want to remove.

For example, I might get back:

  [
   {
    "Name": "blah",
    "Date": "1992-02-18T00:00:00.000Z",
    "Language": "English",
  },
   {
    "Name": "blahzay",
    "Date": "1998-02-18T00:00:00.000Z",
    "Language": "French",
  },       {
    "Name": "blah",                     // same name, no problem
    "Date": "1999-02-18T00:00:00.000Z", // different date
    "Language": "English",             // but same language
  },
 ]

So I want to check that no two objects have a key with the same "Language" value (in this case, "English").

I would like to get the general process of filtering out the entire object if it's "Language" value is duplicated, with the extra issue of not having the same number of objects returned each time. So, allowing for dynamic number of objects in the array.

There is an example here: Unexpeected result when filtering one object array against two other object arrays

but it's assuming that you have a set number of objects in the array and you are only comparing the contents of those same objects each time.

I would be looking for a way to compare

  arrayName[eachObject].Language === "English"

and keep one of the objects but any others (an unknown number of objects) should be filtered out, most probably using .filter() method along with .map().

1
  • In the event that languages repeat, do you want to keep the first, or second instance? Commented Feb 18, 2020 at 19:58

4 Answers 4

1

The below snippets stores the languages that have been encountered in an array. If the current objects language is in the array then it is filtered out. It makes the assumption that the first object encountered with the language is stored.

const objs = [
   {
    "Name": "blah",
    "Date": "1992-02-18T00:00:00.000Z",
    "Language": "English",
  },
   {
    "Name": "blahzay",
    "Date": "1998-02-18T00:00:00.000Z",
    "Language": "French",
  },       {
    "Name": "blah",                     // same name, no problem
    "Date": "1999-02-18T00:00:00.000Z", // different date
    "Language": "English",             // but same language
  },
 ],
 presentLanguages = [];
 let languageIsNotPresent;
 const objsFilteredByLanguage = objs.filter(function (o) {
  languageIsNotPresent = presentLanguages.indexOf(o.Language) == -1;
  presentLanguages.push(o.Language);
  return languageIsNotPresent;
 });
 console.log(objsFilteredByLanguage);

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

3 Comments

I like this but having trouble understanding what's happening. So it's looping through the objects in the array ("(o)") and for each, checking if it's in the array (languageIsNotPresent is either true or false) then, no matter if the value is true or false, adding it to the presentLanguages array, then returning either true or false to finish the loop. Is the final return nullifying the previous addition to the array?
In this case presentLanguages is providing the filter, since the request is to only let one object through per language. the js Array.filter takes a bool return value. If true then the the item is present in the final filtered array if its false then its not. Thus by using indexOf == -1 we only return true if the languageIsNotPresent and that item is added to our final array. So the return doesnt nullify the previous addition because they are 2 separate arrays. 1 acting as a filter and the other a final filtered product.
Thank you. It's a very nice, succinct function.
1

You could take a hash table and filter the array by checking Name and Language.

var array = [{ Name: "blah", Date: "1992-02-18T00:00:00.000Z", Language: "English" }, { Name: "blahzay", Date: "1998-02-18T00:00:00.000Z", Language: "French" }, { Name: "blah", Date: "1999-02-18T00:00:00.000Z", Language: "English" }],
    hash = {},
    result = array.filter(({ Name, Language }) => {
        var key = `${Name}|${Language}`;
        if (!hash[key]) return hash[key] = true;
    });

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

Comments

1

Using Set makes it easy to remove duplicates for as many keys as you like. I tried to be as verbose as possible so that each step was clear.

var objects = [{ "Name": "blah", "Date": "1992-02-18T00:00:00.000Z", "Language": "English", }, { "Name": "blah", "Date": "1998-02-18T00:00:00.000Z", "Language": "French", }, { "Name": "blah", "Date": "1999-02-18T00:00:00.000Z", "Language": "English" }];

function uniqueKeyVals(objects, key) {
  const objVals = objects.map(object => object[key]); // ex. ["English", "French", "English"]  
  return objects.slice(0, new Set(objVals).size);     // ex. { "English", "French" }.size = 2
}

function removeKeyDuplicates(objects, keys) {
  keys.forEach(key => objects = uniqueKeyVals(objects, key));
  return objects;
}

// can also use uniqueKeyVals(key) directly for just one key
console.log("Unique 'Language': \n", removeKeyDuplicates(objects, ["Language"]));
console.log("Unique ['Language', 'Name']: \n", removeKeyDuplicates(objects, ["Language", "Name"]));

1 Comment

That works. I will run a few tests and see if it stays on it's feet when getting a variety of data back from the api. I will also poke around with the code until I understand completely what's happening with each function.
0

I would use the underscore module for JavaScript and the unique function in this scenario. Here is a sample array of data objects:

let data = [{
    name: 'blah',
    date: Date.now(),
    language: "en"
},
{
    name: 'noblah',
    date: Date.now(),
    language: 'es'
},
{
    name: 'blah',
    date: Date.now(),
    language: 'en'
}];

Then we can use the unique function in the underscore library to only return a copy of the data that has unique values associated with the language key:

const result = _.unique(data, 'language');

2 Comments

This answer does return the output the OP is looking for so someone would need to explain that downvote. That's puzzling. I'd welcome anyone to run this code and test it for themselves.
my guess is the down vote stems from 2 things: 1) reliance on a library instead of vanilla js when the op didnt specify a desire for that library 2) you didnt use the data example that the op supplied for your answer. However i agree a down vote without explanation is frustrating.

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.