Groceries function from JS practice: arrays, loops, objects, iterators

THE CODE DOWN BELOW IS A FINAL SOLUTION FROM CODECADEMY. I JUST NEED TO UNDERSTAND HOW IT WORKS.

Hello everyone, I’m having a hard time understanding this code from the practice. Can you please explain how this code works. Specifically, the IF ELSE part where the index is 0 and list length is 3 - 2 which is 1. So the iteration added a comma after the first string and when the second iteration goes the index is 1 and list length is still 3 - 2 which is 1 from here it goes to ELSE IF statement because previous one came out as FALSE. Here index is 1 and list length is still 3 - 2 is 1 that means it should add “AND” instead of ", ". I’m stuck on this part. (It would be great for CODECADEMY developers to include comment on their solutions for us students to understand their code)

Here is the instruction: Write a function groceries() that takes an array of object literals of grocery items. The function should return a string with each item separated by a comma except the last two items should be separated by the word 'and' . Make sure spaces ( ' ' ) are inserted where they are appropriate.

const groceries = list => {
  let listString = ''

  for (let i=0; i<list.length; i++) {
    listString += list[i].item;
    if (i < list.length - 2) {
      listString += ', ';
    } else if (i == list.length - 2){
      listString += ' and ';
    }
  }
  
  return listString;
}

groceries( [{item: 'Carrots'}, 
                   {item: 'Hummus'}, 
                   {item: 'Pesto'}, 
                   {item: 'Rigatoni'}] );

Not sure that is helping, eh?

sorry its a typo. lol

First question to ask is, are we mutating the array or in need of the index? In many cases neither, which is the case here. If all we want is access to the data, without a care for where it sits, then access the data points with of.

1 Like

Here is the instruction: Write a function groceries() that takes an array of object literals of grocery items. The function should return a string with each item separated by a comma except the last two items should be separated by the word 'and' . Make sure spaces ( ' ' ) are inserted where they are appropriate.

Morning,
Remember, whilst the index starts at 0, the length will be the actual length (i.e. 4 in this case, not 3).

1 Like

Hopefully you have this by now - it gave me a headache as I was console.logging instead of returning!

The Codecademy solution is saying:

//Add the word, no matter where it is =>
listString += list[i].item;
//But if it's LESS than the second to last word always put a comma afterwards (Remember the last word would be Length-1)=>   
 if (i < list.length - 2) {
      listString += ', ';
//Otherwise, if it is the second to last word, make sure you put 'and' after it.
    } else if (i == list.length - 2){
      listString += ' and ';
1 Like

Hi all,

The response from @pjbentham helped me understand what is happening in the solution, but I want to make sure I understand the list[i].item part. Is the dot notation in this line of code just allowing us to create an object property in the list array?

//Add the word, no matter where it is =>
listString += list[i].item;
//But if it's LESS than the second to last word always put a comma afterwards (Remember the last word would be Length-1)=>   
 if (i < list.length - 2) {
      listString += ', ';
//Otherwise, if it is the second to last word, make sure you put 'and' after it.
    } else if (i == list.length - 2){
      listString += ' and ';

Thanks!

list[i] must be an object with the property, ‘item’. We’d need to see the complete array to be certain, but it would not have .item if there was no item property.

1 Like

With nested ternary operator function can be simplified (Making it readable and easy to understand).

const groceries = (arr) => {
    const groceryList = arr.map(el => el.item)
    return groceryList.length === 1 ? groceryList[0] : (groceryList.length === 2 ? groceryList.join(' and ') : groceryList.slice(0,groceryList.length-2).join(', ') + ', ' + groceryList.slice(-2).join(' and '))
}
2 Likes

My solution. Long code. The idea was not to specify the .item key specifically, in order for the function to be universal. The function takes the value of the first key in each object.

const groceries = (array) => {
  let text = '';
  array.forEach(object => {
    if(object !== array[array.length-1] && object !== array[array.length-2]){   

        text = text + object[Object.keys(object)[0]] + ', ';       
    }
    else if(object == array[array.length-2]){
      
        text = text + object[Object.keys(object)[0]] + ' and ';
      
    }
    else{
        text = text + object[Object.keys(object)[0]];
    }
    });
  return text;
}
console.log(groceries( [{notitem: 'Carrots', packaging: 'bag'}, {item: 'Hummus'}, {item: 'Pesto'}, {item: 'Rigatoni'}] ));

// prints: Carrots, Hummus, Pesto and Rigatoni

What am I missing here? Should that not be item like all the rest of the objects?

Yeah, it should be :slight_smile: I tried to show that it doesn’t matter what the name of the key is. The function will work properly anyway.

console.log(groceries([{vegetable: 'Carrots'},  {sauce: 'Pesto'}, {pasta: 'Rigatoni'}]));
// prints: Carrots, Pesto and Rigatoni

I wanted to complicate the task a little.

1 Like

If it helps you learn there is no fault in that. We learn by doing, regardless the interim outcomes.

The idea was and is to be able to access the same key in different objects, which is how they relate to each other. They are not just members in the same list, they also share the same properties.

items = [
  {
    item: 'x',
    unit: 'a',
    quantity: 1
    budget: '$'
  },
  {
    item: 'y',
    unit: 'b',
    quantity: 1
    budget: '$'
  },
  {
    item: 'z',
    unit: 'c',
    quantity: 1
    budget: '$'
  }
]
let budget = 0
for (let x of items) {
    budget += x.budget  // pretend this is a float
}
console.log(budget)
1 Like

Challenging, this one! Noticed I resorted to extracting the values into an array instead of working with the objects themselves - it wasn’t a conscious choice, but I’ll keep these things in mind. Here’s my solution:

// Write function below
const groceries = arr => {
  const array = [];
  arr.forEach(obj => {
    array.push(obj.item);
  });

  let str = '';
  for (let i=0; i < array.length; i++) {
    if (i === 0) {
      str += array[0];
    } else if (i === (array.length-1)) {
      str += ' and ' + array[i];
    } else {
      str += ', ' + array[i];
    }
  }

  return str;
}

console.log(groceries([{item: 'Carrots'}, {item: 'Hummus'}, {item: 'Pesto'}, {item: 'Rigatoni'}]));
1 Like