0

Say I have an array of objects like so:

[{name: John, year: 2011, age: "65+", value: 2},
{name: John, year: 2012, age: "65+", value: 5},
{name: Bob, year: 2011, age: "18 under", value: 2}]

I'd like to convert this array of objects into the following:

[{name: John, age: "65+", 2011: 2, 2012: 5},
{name: Bob, age: "18 under", 2011: 2, 2012: NA}]

You'll notice that I've converted the year values into actual keys. How do I go about this efficiently?

9
  • Are the entries for a given name always together in the array (contiguous)? Commented Apr 29, 2020 at 19:01
  • I'm confused about your requirements. There's probably going to have to be an "inner" loop somewhere, and inner loops don't necessarily make an algorithm inefficient. Commented Apr 29, 2020 at 19:02
  • @Jerfov2, If there is an efficient way of doing it even with inner loops I am ok. Commented Apr 29, 2020 at 19:04
  • @Ry yes you can guarantee that the names will be together Commented Apr 29, 2020 at 19:05
  • sounds like premature optimization. unless you are dealing with a truly enormous amount of values, you really don't need to worry about optimizing this. but right, you can use a map of counters Commented Apr 29, 2020 at 19:12

2 Answers 2

2

You could group the data and collect all keys and apply later the missing years.

var data = [{ name: 'John', year: 2011, age: "65+", value: 2 }, { name: 'John', year: 2012, age: "65+", value: 5 }, { name: 'Bob', year: 2011, age: "18 under", value: 2 }],
    years = new Set;
    result = Object
        .values(data.reduce((r, { name, year, value, ...o }) => {
            r[name] = r[name] || { name, ...o };
            r[name][year] = value;
            years.add(year);
            return r;
        }, {}))
        .map(
            (y => o => ({ ...y, ...o }))
            (Object.fromEntries([...years].map(y => [y, NaN])))
        );

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

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

6 Comments

You should not add all dates to each object, so the second object of the array should not have a key "2012" at all, and so on if there are lot of dates, then lot of useless keys are added to each object
@SaymoinSam, please see op's request.
I don't know if he really wants that behaviour or that's what he tried to do!
This looks promising. Would this work if we added another variable, like "Age Group"?
@somethingstrang, how does the data look like and how the result?
|
0

You can do it by processing the array one element at a time and creating a new object every time you see a new name:

function* groupByName(entries) {
    let group = null;

    for (const {name, year, value} of entries) {
        if (group === null || group.name !== name) {
            if (group !== null) {
                yield group;
            }
            
            group = {name};
        }

        group[year] = value;
    }

    if (group !== null) {
        yield group;
    }
}

const entries = [
    {name: 'John', year: 2011, value: 2},
    {name: 'John', year: 2012, value: 5},
    {name: 'Bob', year: 2011, value: 2},
];

console.log([...groupByName(entries)]);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.