0

Given the following values:

const values = ['name1|engine1|color1', 'name2|engine2|color2', 'name3|engine3|color3']

I would like to create an array for the values ​​of the same position, like this:

cars = {
  names: ['name1', 'name2', 'name3'],
  engines: ['engine1', 'engine2', 'engine3'],
  colors: ['color1', 'color2', 'color3'],
  ...other properties
}

I tried to do it this way:

values.reduce((acc, value) => {
  const [name, engine, color] = value.split('|')

  acc.names.push(name)
  acc.engines.push(engine)
  acc.colors.push(color)

  return acc
}, {})

The problem is that acc.name, acc.engine and acc.color don't exist yet, and it gives an error on push. What would be a way to do this cleanly, taking into account that they will have other properties?

3
  • 1
    Can't you set proper initial value for the reduce? Instead of empty object {}, use { names: [], engines: [], colors: []} instead Commented Apr 30, 2022 at 23:04
  • Set them in advance as @zzz recommended if you know them but you can set them conditionally if they don't exist using logical nullish assignment (acc.names ??= []).push(name). This is most useful when the keys aren't known in advance or are derived from the reduced elements. Commented Apr 30, 2022 at 23:07
  • Thanks, that's exactly what i needed! Commented Apr 30, 2022 at 23:29

3 Answers 3

3
  • Case1.

const values = [
  "name1|engine1|color1",
  "name2|engine2|color2",
  "name3|engine3|color3"
];

const cars = {
  names: [],
  engines: [],
  colors: []
};

const result = values.reduce((acc, value) => {
  const [name, engine, color] = value.split("|");

  acc.names.push(name);
  acc.engines.push(engine);
  acc.colors.push(color);

  return acc;
}, cars);

console.log(result);

  • Case2.

const values = [
  "name1|engine1|color1",
  "name2|engine2|color2",
  "name3|engine3|color3"
];

const result = values.reduce((acc, value) => {
  const [name, engine, color] = value.split("|");

  (acc.names ??= []).push(name);
  (acc.engines ??= []).push(engine);
  (acc.colors ??= []).push(color);

  return acc;
}, {});

console.log(result);

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

Comments

1

If you have a very long property names, you can also do this:

const values = [
  "name1|engine1|color1",
  "name2|engine2|color2",
  "name3|engine3|color3"
];

const keys = ["names", "engines", "colors", ...];

const results = values.reduce((acc, value) => {
  const segments = value.split("|");
  keys.forEach((key, index) => {
    (acc[key] ??= []).push(segments[index]);
  });
  return acc;
}, {});

console.log(results)

Comments

0

Object.fromEntries makes this easy to do this in a simple map call:

const reconstruct = (names, values) =>
  values .map (v => Object .fromEntries (v .split ('|') .map ((v, i) => ([names[i], v]))))

console .log (reconstruct (
  ['name', 'engine', 'color'], [
  'name1|engine1|color1', 
  'name2|engine2|color2', 
  'name3|engine3|color3'
]))
.as-console-wrapper {max-height: 100% !important; top: 0}

We convert each of our strings into something like [['name', 'name1'], ['engine', 'engine1'], ['color', 'color1']] then call Object.fromEntries on that.

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.