JavaScript - How to Map a list of names to a specified key using reduce

Viewed 119

I want to learn the javascript reduce function. I have implemented the following using a different solution, but want to achieve the same through reduce.

I have an alphabets array and names array.

alphabets: ['A','B','C','D','E','F','G','H','I','J','K','L',
        'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
names: [{ name: 'Apple' },{ name: 'Apricot' },{ name: 'Avocados' },{ name: 'Almond' },
        { name: 'Blueberries' }, { name: 'Bing Cherry' },{ name: 'Breadfruit' },{ name: 'Bananas' },
        { name: 'Cherries' },{ name: 'Custard-Apple' },{ name: 'Carrot' },{ name: 'Cranberries' },
        { name: 'Dates' }, { name: 'Dragon Fruit' },{ name: 'Durian' },
        { name: 'Grapefruit' },{ name: 'Grapes' },{ name: 'Gooseberries' },{ name: 'Guava' },],

Using javascript reduce funtion, I want to map key value pair like,

A: 'Apple','Apricot','Avocados','Almond'
B: 'Blueberries', 'Bing Cherry', 'Breadfruit', 'Bananas'
C: 'Cherries', 'Custard-Apple', 'Carrot', 'Cranberries'
D: 'Dates', 'Dragon Fruit', 'Durian'

Key A should contain a list of fruits that start with A, Key B should contain a list of fruits that start with B. Kindly help me with this.

7 Answers

You could take a logical nullish assignment ??= operator fro assigning an array to a cetrain property and push the actual destrctured name.

const 
    names = [{ name: 'Apple' }, { name: 'Apricot' }, { name: 'Avocados' }, { name: 'Almond' }, { name: 'Blueberries' }, { name: 'Bing Cherry' }, { name: 'Breadfruit' }, { name: 'Bananas' }, { name: 'Cherries' }, { name: 'Custard-Apple' }, { name: 'Carrot' }, { name: 'Cranberries' }, { name: 'Dates' }, { name: 'Dragon Fruit' }, { name: 'Durian' }, { name: 'Grapefruit' }, { name: 'Grapes' }, { name: 'Gooseberries' }, { name: 'Guava' }],
    grouped = names.reduce(
        (r, { name }) => ((r[name[0].toUpperCase()] ??= []).push(name), r),
        {}
    );

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

You can just use first letter of name to be a key of value.

const groupedNames = names.reduce((acc, item) => {
  const firstLetter = item.name.charAt(0);
  if (!acc[firstLetter]) {
    acc[firstLetter] = [item.name];
    return acc;
  };
  acc[firstLetter].push(item.name);
  return acc;
}, {})

You don't need the alphabet array, you can just reduce based on the first letter:

names.reduce((obj, {name}) => {
    const firstLetter = name[0];
    if (firstLetter in obj) {
        obj[firstLetter].push(name);
    } else {
        obj[firstLetter] = [name];
    }
    return obj;
}, {});

You can get the first character and use it as a key in the object accumulator of Array#reduce.

If the key is present add the word starting with the key in the corresponding array:

const alphabets = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
const names = [{ name: 'Apple' },{ name: 'Apricot' },{ name: 'Avocados' },{ name: 'Almond' },
{ name: 'Blueberries' }, { name: 'Bing Cherry' },{ name: 'Breadfruit' },{ name: 'Bananas' },
{ name: 'Cherries' },{ name: 'Custard-Apple' },{ name: 'Carrot' },{ name: 'Cranberries' },
{ name: 'Dates' }, { name: 'Dragon Fruit' },{ name: 'Durian' },
{ name: 'Grapefruit' },{ name: 'Grapes' },{ name: 'Gooseberries' },{ name: 'Guava' }];

const grouped = names.reduce((r, {name}) => {
  const key = name && name[0].toUpperCase();
  r[key] = r[key] || [];
  r[key].push(name);
  return r;
}, {});

console.log(grouped);

You can try with reduce and use filter along with map to get values from names array

let alphabets = ['A','B','C','D','E','F','G','H','I','J','K','L',
        'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
        
let names = [{ name: 'Apple' },{ name: 'Apricot' },{ name: 'Avocados' },{ name: 'Almond' },
        { name: 'Blueberries' }, { name: 'Bing Cherry' },{ name: 'Breadfruit' },{ name: 'Bananas' },
        { name: 'Cherries' },{ name: 'Custard-Apple' },{ name: 'Carrot' },{ name: 'Cranberries' },
        { name: 'Dates' }, { name: 'Dragon Fruit' },{ name: 'Durian' },
        { name: 'Grapefruit' },{ name: 'Grapes' },{ name: 'Gooseberries' },{ name: 'Guava' }];
        

let result = alphabets.reduce((acc, letter) => {
    acc[letter] = names.map(x => x.name).filter(name => name[0] === letter);
    return acc;
}, {})

console.log(result);

You can use Array#prototype#reduce with some destructuring to achieve the desired grouping.

const names = [{ name: 'Apple' },{ name: 'Apricot' },{ name: 'Avocados' },{ name: 'Almond' },
        { name: 'Blueberries' }, { name: 'Bing Cherry' },{ name: 'Breadfruit' },{ name: 'Bananas' },
        { name: 'Cherries' },{ name: 'Custard-Apple' },{ name: 'Carrot' },{ name: 'Cranberries' },
        { name: 'Dates' }, { name: 'Dragon Fruit' },{ name: 'Durian' },
        { name: 'Grapefruit' },{ name: 'Grapes' },{ name: 'Gooseberries' },{ name: 'Guava' }];
        
const grouping = names.reduce((acc, { name }) => {
  // Destructure the name, as its an iterable and take the first character only
    let [firstChar] = name;
    firstChar = firstChar.toUpperCase();
    acc[firstChar] = (acc[firstChar] || []).concat(name);
    return acc;
}, Object.create(null));

console.log(grouping);

You can also use map and filter to do this as you need the whole alphabet array, Just another way to approach the problem

const names=[{ name: 'Apple' },{ name: 'Apricot' },{ name: 'Avocados' },{ name: 'Almond' },
        { name: 'Blueberries' }, { name: 'Bing Cherry' },{ name: 'Breadfruit' },{ name: 'Bananas' },
        { name: 'Cherries' },{ name: 'Custard-Apple' },{ name: 'Carrot' },{ name: 'Cranberries' },
        { name: 'Dates' }, { name: 'Dragon Fruit' },{ name: 'Durian' },
        { name: 'Grapefruit' },{ name: 'Grapes' },{ name: 'Gooseberries' },{ name: 'Guava' }]

const alphabets = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
  'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
];


const x = alphabets.map(x => ({
  [x]: [...names.filter(name => name.name.startsWith(x)).map(m => m.name)]
}));

console.log(x);

Related