0

The situation that I'm dealing with is that I have an array of objects and I would like to filter down to an array where the objects are unique with regard to one property keeping the last instance.

For example lets say I have an array of files like so:

let files = 
     [
        {
          filename: "filename.txt",
          uploadedBy: "Bob",
          comment: "Gee whiz"
        },
          filename: "filename.txt",
          uploadedBy: "Jane",
          comment: "Golly"
        },
          filename: "otherFile.txt",
          uploadedBy: "Bob",
          comment: "Shucks"
        },
          filename: "filename.txt",
          uploadedBy: "Henry",
          comment: "Gee Willikers"
        },
     ]

I want the objects with distinct filenames and I want the last instance of each filename.

     [
          filename: "otherFile.txt",
          uploadedBy: "Bob",
          comment: "Shucks"
        },
          filename: "filename.txt",
          uploadedBy: "Henry",
          comment: "Gee Willikers"
        },
     ]

Is there a concise way of doing this? All I can come up with is a pretty long method to first map the array to get just the filenames, then find the last instance of each filename or something.

The following question is similar but keeps the first value not the last : Get all unique values in a JavaScript array (remove duplicates)

 function onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
}

// usage example:
var a = ['a', 1, 'a', 2, '1'];
var unique = a.filter( onlyUnique ); // returns ['a', 1, 2, '1']
Word Rearranger
  • 1,306
  • 1
  • 16
  • 25
Brian H
  • 1,033
  • 2
  • 9
  • 28

3 Answers3

0

You could first get only unique file names from the array, then simply map over them and look for the first element in the reversed files array.

const f = [{"filename":"filename.txt","uploadedBy":"Bob","comment":"Gee whiz"},{"filename":"filename.txt","uploadedBy":"Jane","comment":"Golly"},{"filename":"otherFile.txt","uploadedBy":"Bob","comment":"Shucks"},{"filename":"filename.txt","uploadedBy":"Henry","comment":"Gee Willikers"}].reverse();

const unique = [...new Set(f.map(({ filename }) => filename))]
         .map((name) => f.find(({ filename }) => filename === name)); 

console.log(unique);
kind user
  • 40,029
  • 7
  • 67
  • 77
0

Reduce to a Map, and use the filename as the key to set the item, and then spread the Map.values() iterator back to an array:

const files = [{"filename":"filename.txt","uploadedBy":"Bob","comment":"Gee whiz"},{"filename":"filename.txt","uploadedBy":"Jane","comment":"Golly"},{"filename":"otherFile.txt","uploadedBy":"Bob","comment":"Shucks"},{"filename":"filename.txt","uploadedBy":"Henry","comment":"Gee Willikers"}]

const result = [...
  files.reduce((m, o) => m.set(o.filename, o), new Map())
.values()]

console.log(result)
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
0

You could use a Map which has each unique filename as key and the the file object as value. If another entry with the same filename is found, it will overwrite the previous value. So, it will always be the last occurrence. Then get the values of the Map to just the file objects

const files=[{filename:"filename.txt",uploadedBy:"Bob",comment:"Gee whiz"},{filename:"filename.txt",uploadedBy:"Jane",comment:"Golly"},{filename:"otherFile.txt",uploadedBy:"Bob",comment:"Shucks"},{filename:"filename.txt",uploadedBy:"Henry",comment:"Gee Willikers"},];

const map = new Map(files.map(f => [f.filename, f])),
      unique = Array.from(map.values());
      
console.log(unique)
adiga
  • 34,372
  • 9
  • 61
  • 83