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

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.