My solution

‘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 = arr => {
  let newArr = [];
  for(let i = 0; i < arr.length; i++) {
    newArr.push(arr[i].item);
  }
  if(newArr.length < 2) {
    return newArr.join('');
  } else {
 let final = newArr.pop(); 
 return newArr.join(', ') + ' and ' + final;
  }
}

console.log(groceries( [{item: 'Carrots'}, {item: 'Hummus'}, {item: 'Pesto'}, {item: 'Rigatoni'}]));
console.log(groceries( [{item: 'Bread'}, {item: 'Butter'}]));
console.log(groceries( [{item: 'Cheese Balls'}]));

I wrote the code above to solve the challenge above and I feel so great that it worked. Most of the solutions I found online, I couldn’t wrap my mind around. So, I decide to solve it with code that I understood and had just learnt because I didn’t believe that I will be challenged with something beyond the scope of what had just been taught.

4 Likes

Hey! My code for this exercise (https://www.codecademy.com/paths/full-stack-engineer-career-path/tracks/fscp-javascript-syntax-part-ii/modules/fecp-practice-javascript-syntax-arrays-loops-objects-iterators/articles/fecp-javascript-practice-arrays-loops-objects-iterators) was pretty similar to yours:

// Write function below const groceries = (array) => { let itemArray = []; for (i = 0; i - array.length; i++){ itemArray.push(array[i].item); } if (itemArray.length > 1){ console.log(itemArray.slice(0, itemArray.length - 1).join(', ') + " and " + itemArray.slice(-1)); } else if (itemArray.length = 1){ console.log(itemArray[0]); } }

Can someone more experienced tell me if there’s any issues with this code?
I know it works with the examples provided, but it doesn’t look anything like the answer from Codecademy, so I’m wondering if there’s a reason it shouldn’t be approached this way from someone with more experience.

Without helping you overcome the issues in your code, perhaps you might gain some insight from what intuition we brought about…

const groceries = u => {
  const m = u.map(x => x.item)
  if (m.length === 1) return m[0]
  const v = m.join(', ')
  const i = v.lastIndexOf(',')
  return v.slice(0, i) + ' and' + v.slice(i + 1)
}

As a rule, for me, anyway, there is no logging in the function. Leave that to the caller.

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

We have sort of the same intuition, so you cannot be that far off.

Given that we hate concatenation,

  return `${v.slice(0, i)} and${v.slice(i + 1)}`

Be interested in how you tackled the previous two. Again, acting intuitively we sketched out some working solutions that likely differ, somewhat, from yours.

const factorial = n => n === 1 ? 1 : n * factorial(n - 1)
function subLength(string, char) {
  const x = string.split(char)
  if (x.length === 3) {
    return x[1].length + 2
  }
  return 0
}

Not a big fan of recursion in cases where iteration is quicker, but it fit the one-liner expression so I went with it. As for the sublength, it draws on our understanding of the .split() method.


Regardless whether one passed this phase of the lessons, did we learn anything? Stop on a dime if you have any doubts. Stop and go back a few steps and scratch start from there.

We don’t want the baggage of misunderstanding on our shoulders going forward. Clear the airwaves.


Off topic

One is not a big fan of descriptive variable names where they are not needed. groceries() has five variables, all of which are easily identified and their role interpreted from the code. Do we need to give them longer names? No. As symbols they are a good and proper fit. No documentation required.


Other than,

// Return a grammatical list in prose form.

as the opening line of the function, and any other parameter description that could be added. Once we know what it does it is kind of moot to get into documentation. Me, personally, I love reading code. Documentation is for when questions arise.

3 Likes

Thank you so much!

In summary, just to make sure I understand, you suggest:

  1. Leave logging to the caller,
  2. Avoid concatenation (use interpolation),
  3. Prefer iteration over recursion when quicker,
  4. Use the previous exercises to inform solutions to the current exercise,
  5. Keep variable names simple,
    and
  6. Add description, but only where necessary.

I just want to make sure I’m getting everything. I’m still quite new to all programming so these general principles are really helpful to me (and not necessarily intuitively obvious to me yet, so I’m really grateful for the time you spent to share these thoughts.)

Thank you,
Elly

4 Likes

You’re welcome. To all six points, I concur. You’ve read clearly. Bear in mind these are musings, in the philosophical sense, but also in the personal sense since this is how I write for myself. Some of this may well be applicable in the real world, and I would hope this so. They all make sense, which I’m sure we can agree.

3 Likes

Hey please sam can you explain the ‘if…else’ block I don’t understand the final part especially how the .pop() method works in this code.

Hi Erasun.
I used the .pop(), to remove the last item in the array, if the array.length was > 1 but then, I concatenated it with the other items in the list. The aim was to ensure that the last 2 items were separated by ‘and’.

I Hope I answered your question.

const groceries = u => {
  const m = u.map(x => x.item)
  if (m.length === 1) return m[0]
  const v = m.join(', ')
  const i = v.lastIndexOf(',')
  return v.slice(0, i) + ' and' + v.slice(i + 1)
}
const groceries = arr => {
  let newArr = [];
  for(let i = 0; i < arr.length; i++) {
    newArr.push(arr[i].item);
  }
  if(newArr.length < 2) {
    return newArr.join('');
  } else {
 let final = newArr.pop(); 
 return newArr.join(', ') + ' and ' + final;
  }
}

We can learn from each other, as it stands.

if (m.length === 1) return m[0]

That was letting an empty array into code that was not expecting one. The outcome was,

' and '.
if (m.length < 2) return m[0]

In this implementation, m[0] is undefined if the array is empty, and that is the return, now.


All of which brings us to this consolidation…

const groceries = u => {
  const m = u.map(x => x.item)
  if (m.length < 2) return m[0]
  const p = m.pop()
  return `${m.join(', ')} and ${p}`
}
1 Like

Thank you Sam now I get it

Thank you so much for this. I have been working my ■■■ off on this. I thought I had it all figured out, but for some reason didn’t think to use .pop() to remove the last word and then add it to the end. This one was a huge eye opener! Thank you again!

1 Like

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.