2

I'm drawing data from a database and ending up with an array of objects each containing waiter names and the the days they have worked. I want to dynamically restructure the array by condensing it to a single object with two property value pairs per waiter. One property for the name and another for the days working.

I am really curious to see your feedback. I started off by extracting the names and removing duplicates. Leaving me with an array like this: let waiterNames = ['John','Mark','Jess'].

Then I was attempting a double for of loop and somehow creating a new array of objects, but I'm stuck.

for (entry in waiterInfo) {
    for (waiter in waiterNames) {
        if (entry.waiters == waiter) {
        ???
        }
    }
}

waiterInfo is what I start with, newInfo is what I want to achieve. I need this to happen dynamically because the data drawn from the database is unpredictable.

let waiterInfo = [{ waiters: 'John', weekdays: 'Monday' },
{ waiters: 'John', weekdays: 'Tuesday' },
{ waiters: 'John', weekdays: 'Wednesday' },
{ waiters: 'Mark', weekdays: 'Monday' },
{ waiters: 'Mark', weekdays: 'Tuesday' },
{ waiters: 'Jess', weekdays: 'Monday' },
{ waiters: 'Jess', weekdays: 'Tuesday' },
{ waiters: 'Jess', weekdays: 'Wednesday' },
{ waiters: 'Jess', weekdays: 'Thursday' }]
let newInfo = [{ waiters: 'John', weekdays: 'Monday, Tuesday, Wednesday'},
{ waiters: 'Mark', weekdays: 'Monday, Tuesday' },
{ waiters: 'Jess', weekdays: 'Monday, Tuesday, Wednesday, Thursday' }]
6
  • Can you show what the array you get from the DB looks like? Commented Oct 28, 2019 at 10:58
  • Hi, thank you four reply. The array is shown above - waiterInfo. I want to change it dynamically to look like newInfo. Commented Oct 28, 2019 at 10:59
  • Which DB do you use? Perhaps it would be easier to do this thing directly in the db. Commented Oct 28, 2019 at 11:33
  • This is a valid point - but I was curious to see how to solve this problem anyhow. I'm using postgreSQL. My table has four columns: id, waiter_username, weekdays_working and waiters_id which is unique for each waiter. I was attempting to write a query that would remove the duplicate waiters names, but was unsuccessful. This is the query I used which returned the waiterInfo array above -> select waiter_username as waiters, weekdays_working as weekdays from waiters order by waiter_username; Commented Oct 28, 2019 at 12:02
  • @Warwick: select waiter_username, array_agg(weekdays_working) as weekdays from waiters group by waiter_username should do the trick. Commented Oct 28, 2019 at 13:55

3 Answers 3

2

You can use a map alongside reduce:

let waiterInfo = [{ waiters: 'John', weekdays: 'Monday' },
  { waiters: 'John', weekdays: 'Tuesday' },
  { waiters: 'John', weekdays: 'Wednesday' },
  { waiters: 'Mark', weekdays: 'Monday' },
  { waiters: 'Mark', weekdays: 'Tuesday' },
  { waiters: 'Jess', weekdays: 'Monday' },
  { waiters: 'Jess', weekdays: 'Tuesday' },
  { waiters: 'Jess', weekdays: 'Wednesday' },
  { waiters: 'Jess', weekdays: 'Thursday' }
]


const map = new Map()

const newInfo = waiterInfo.reduce((a, o) => {
  const i = map.get(o.waiters)
  if(i !== undefined) {
    a[i].weekdays = [a[i].weekdays, o.weekdays].join(', ')
  } else {
    map.set(o.waiters, a.push(o) - 1)
  }
  return a
}, [])

console.log(newInfo)

This code's time complexity is O(n), since we are using a map.

(Also, this is one of the only times I've seen push's return value be useful 😜)

Sign up to request clarification or add additional context in comments.

3 Comments

Incredible - you guys are very good. I am very inspired by your feedback!
@Warwick No problem, glad to help. If you need more help, be it understanding how this code works or anything else, feel free to ask.
I'm going on lunch now.. will attempt implementing and understanding the code into my program afterwards. Will post a question here if I don't understand - but think I can figure it out with all the information I've obtained in this thread. Thank you. =)
1

You can do:

const waiterInfo = [{ waiters: 'John', weekdays: 'Monday' },{ waiters: 'John', weekdays: 'Tuesday' },{ waiters: 'John', weekdays: 'Wednesday' },{ waiters: 'Mark', weekdays: 'Monday' },{ waiters: 'Mark', weekdays: 'Tuesday' },{ waiters: 'Jess', weekdays: 'Monday' },{ waiters: 'Jess', weekdays: 'Tuesday' },{ waiters: 'Jess', weekdays: 'Wednesday' },{ waiters: 'Jess', weekdays: 'Thursday' },]

const result = Object
  .values(
    waiterInfo.reduce((a, { waiters, weekdays }) => {
      a[waiters] = a[waiters] || { waiters, weekdays: [] }
      a[waiters].weekdays.push(weekdays)
      return a
    }, {})
  )
  .map(({ waiters, weekdays }) => ({ waiters, weekdays: weekdays.join(', ') }))

console.log(result)

Comments

0

The easiest way to do this is to use a temporary Map to keep track of the objects for the waiters you've seen before, so you can add to their list of days.

const waiterMap = new Map();
const newInfo = [];
for (const {waiters, weekdays} of waiterInfo) {
    let entry = waiterMap.get(waiters);
    if (!entry) {
        // New waiter, create the object and put it in the map and result array
        const copy = {waiters, weekdays};
        waiterMap.set(waiters, copy);
        newInfo.push(copy);
    } else {
        // Existing entry, just add to it
        entry.weekdays += `, ${weekdays}`;
    }
}

Live Example:

let waiterInfo = [{ waiters: 'John', weekdays: 'Monday' },
{ waiters: 'John', weekdays: 'Tuesday' },
{ waiters: 'John', weekdays: 'Wednesday' },
{ waiters: 'Mark', weekdays: 'Monday' },
{ waiters: 'Mark', weekdays: 'Tuesday' },
{ waiters: 'Jess', weekdays: 'Monday' },
{ waiters: 'Jess', weekdays: 'Tuesday' },
{ waiters: 'Jess', weekdays: 'Wednesday' },
{ waiters: 'Jess', weekdays: 'Thursday' }];

const waiterMap = new Map();
const newInfo = [];
for (const {waiters, weekdays} of waiterInfo) {
    let entry = waiterMap.get(waiters);
    if (!entry) {
        // New waiter, create the object and put it in the map and result array
        const copy = {waiters, weekdays};
        waiterMap.set(waiters, copy);
        newInfo.push(copy);
    } else {
        // Existing entry, just add to it
        entry.weekdays += `, ${weekdays}`;
    }
}

console.log(newInfo);

That avoids modifying the existing data, but you could reuse the original object if you don't care about waiterInfo once you're done.

1 Comment

T.J. Crowder magnificent! I am very impressed by your speed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.