How do I get unique records by comparing the first n characters?

Viewed 73

How do I get every single record of an array string substring?

Example:

sourcefiles = ['a.pdf', 'a_ok.pdf', 'a.csv', 'b_ok.csv', 'b.csv', 'c.pdf']
var uniq = [ ...new Set(sourcefiles)];   //I want the output to be: a, b, c
console.log(uniq)

I tried to add substring:

sourcefiles = ['a.pdf', 'a_ok.pdf', 'a.csv', 'b_ok.csv', 'b.csv', 'c.pdf']
var uniq = [ ...new Set(sourcefiles.substring(0,1))]; 
console.log(uniq)

VM116792:2 Uncaught TypeError: sourcefiles.substring is not a function
    at <anonymous>:2:37

How do I get unique records by comparing the first n characters?

5 Answers

You were close! You just had to use map() to get the substrings, as the array class has no subString() method:

const sourcefiles = ['a.pdf', 'a_ok.pdf', 'a.csv', 'b_ok.csv', 'b.csv', 'c.pdf'];
const uniq = [...new Set(sourcefiles.map(a => a.substring(0,1)))] 
console.log(uniq);

As noted elsewhere, shorter isn't necessarily better. reduce() outperforms creating a new Set. Here it is in one (crammed) line:

const uniq = sourcefiles.reduce((a,s) => { a.includes(s[0]) ? null : a.push(s[0]); return a}, []);

const sourcefiles = ['a.pdf', 'a_ok.pdf', 'a.csv', 'b_ok.csv', 'b.csv', 'c.pdf']
var arr = [ ...sourcefiles].map(i=> i.substring(0,1));
var uniq = [ ...new Set(arr)];

console.log(uniq)

Reduce might work faster than map and Set

sourcefiles = ['a.pdf', 'a_ok.pdf', 'a.csv', 'b_ok.csv', 'b.csv', 'c.pdf']
var uniq = sourcefiles.reduce((acc, cur) => {
  const firstChar = cur.substring(0, 1);
  if (!acc.find(fn => fn.substring(0, 1) === firstChar)) acc.push(cur)
  return acc
}, [])
console.log(uniq)

If you only want the first char then

sourcefiles = ['a.pdf', 'a_ok.pdf', 'a.csv', 'b_ok.csv', 'b.csv', 'c.pdf']
var uniq = sourcefiles.reduce((acc, cur) => {
  const firstChar = cur.substring(0, 1);
  if (!acc.includes(firstChar)) acc.push(firstChar)
  return acc
}, [])
console.log(uniq)

Another, simpler take on reduce: (based upon code comment in OPS code: //I want the output to be: a, b, c)

sourcefiles = ['a.pdf', 'a_ok.pdf', 'a.csv', 'b_ok.csv', 'b.csv', 'c.pdf'];
const out = sourcefiles
  .reduce(
    (acc, n) => {
      acc.includes(n[0]) ? null : acc.push(n[0]); // no-op if found in array
      return acc;
    }, []);
console.log(out);

const sourcefiles = ['a.pdf', 'a_ok.pdf', 'a.csv', 'b_ok.csv', 'b.csv', 'c.pdf']    
const result = sourcefiles.map(singleSourceFile => singleSourceFile.substring(0,1)).filter((v, i, a) => a.indexOf(v) === i);

console.log(result);

One can use substring with 'n' characters defined as a second arg and find unique elements using filter method available in conjunction with indexOf.

Related