-1

In my project, I need to classify an array and convert it to another type of array. The difficulty I encountered was that there was no way to use concise and efficient execution. The following are my input and output:

const input = [{
    "type": 1,
    "color": "Red(268)"
  },
  {
    "type": 1,
    "color": "Blue(583)"
  },
  {
    "type": 2,
    "color": "Blue(185)"
  },
  {
    "type": 4,
    "color": "Red(326)"
  },
  {
    "type": 4,
    "color": "Blue(967)"
  },
  {
    "type": 5,
    "color": "Red(863)"
  }
]
const output = [
  "Type 1: Red(268), Blue(583)",
  "Type 2: Blue(185)",
  "Type 4: Red(326), Blue(967)",
  "Type 5: Red(863)"
]

The following is my method. I use the set() to find out the number of types, and then use for loop to convert it into a string and push into the array, but it cannot be executed continuously, so my function cannot get the correct result, and it is not efficient.

this.ty = 1;
this.result = [];

const set = new Set();
const length = input.filter(item => !set.has(item.type) ? set.add(item.type) : false).length + 1;

for (let i = 1; i < length; i++) {
  const temp = input.filter(x => {
    return x.type === ty;
  })
  if (temp.length < 2) {
    this.result.push(`Type ${ty}: ${temp[0].color}`);
  } else {
    this.result.push(`Type ${ty}: ${temp[0].color}, ${temp[1].color}`);
  }
  this.ty = i + 1;
}

This problem has troubled me for a long time. Can someone provide an easier way to convert this array? Thank you for your help.

const input = [{
    "type": 1,
    "color": "Red(268)"
  },
  {
    "type": 1,
    "color": "Blue(583)"
  },
  {
    "type": 2,
    "color": "Blue(185)"
  },
  {
    "type": 4,
    "color": "Red(326)"
  },
  {
    "type": 4,
    "color": "Blue(967)"
  },
  {
    "type": 5,
    "color": "Red(863)"
  }
]

console.log('input', input);

this.ty = 1;
this.result = [];

const set = new Set();
const length = input.filter(item => !set.has(item.type) ? set.add(item.type) : false).length + 1;

for (let i = 1; i < length; i++) {
  const temp = input.filter(x => {
    return x.type === ty;
  })
  if (temp.length < 2) {
    this.result.push(`Type ${ty}: ${temp[0].color}`);
  } else {
    this.result.push(`Type ${ty}: ${temp[0].color}, ${temp[1].color}`);
  }
  this.ty = i + 1;
}

console.log('result', this.result);

// output
/* const output = [
  "Type 1: Red(268), Blue(583)",
  "Type 2: Blue(185)",
  "Type 4: Red(326), Blue(967)",
  "Type 5: Red(863)"
] */
Simone Rossaini
  • 8,115
  • 1
  • 13
  • 34
Ian
  • 1
  • 1
  • Ultimately, you're trying to do too much at once (grouping and converting to string) . I'd group, then convert to string. Grouping can be found at [Group array items using object](https://stackoverflow.com/q/31688459/215552) – Heretic Monkey May 21 '21 at 13:41
  • @Simone Please don't copy code from external sites to Stack Overflow for OPs. You are changing the license of their copyrighted code. If the OP wants to copy the code, that is their right. – Heretic Monkey May 21 '21 at 13:50
  • What do you mean by "cannot be executed continuously"? What would a "concise and efficient" solution look like? – jarmod May 21 '21 at 14:34
  • @Heretic Monkey is code from OPs, why you talk about copyright? I think he didn't know how use tools <> – Simone Rossaini May 21 '21 at 17:46

4 Answers4

1

You can use the Array.reduce() function to iterate your array and construct a new object.

const input = [{
    "type": 1,
    "color": "Red(268)"
  },
  {
    "type": 1,
    "color": "Blue(583)"
  },
  {
    "type": 2,
    "color": "Blue(185)"
  },
  {
    "type": 4,
    "color": "Red(326)"
  },
  {
    "type": 4,
    "color": "Blue(967)"
  },
  {
    "type": 5,
    "color": "Red(863)"
  }
];

const mappedInput = input.reduce((grouped, {
  type,
  color
}) => {
  if (!grouped.hasOwnProperty(type)) {
    grouped[type] = `Type ${type}: ${color}`;
  } else {
    grouped[type] += `, ${color}`;
  }
  return grouped;
}, {});

console.log(Object.values(mappedInput));

We use an object to provide efficient key lookup and at the end, retrieve just the array of strings that we need.

ChrisG
  • 2,637
  • 18
  • 20
0

Here's a simple, functional solution:

// Get list of unique input types
const types = Array.from(new Set(input.map(x => x.type)));

// Map over unique types, filter for matching inputs, yield all colors
const output = types.map(type => `Type ${type}: ${input.filter(x => x.type == type).map(x => x.color).join(', ')}`);
jarmod
  • 71,565
  • 16
  • 115
  • 122
  • This doesn't really address the efficiency request of the question. You're filtering and mapping through the entire array for each item. – ChrisG May 21 '21 at 14:23
  • @ChrisG agreed, though the requirement here is somewhat ambiguous so I've asked the OP for more clarity. – jarmod May 21 '21 at 14:37
0

You could reduce over the array to create an object that uses the type as a key and an array as a value, pushing new instances into the array with each iteration.

Then map over the Object.entries to produce a new array of strings.

const input = [{"type":1,"color":"Red(268)"},{"type":1,"color":"Blue(583)"},{"type":2,"color":"Blue(185)"},{"type":4,"color":"Red(326)"},{"type":4,"color":"Blue(967)"},{"type":5,"color":"Red(863)"}];

const out = input.reduce((acc, c) => {
  const [ key, value ] = Object.values(c);
  acc[key] = acc[key] || [];
  acc[key].push(value);
  return acc;
}, {});

const result = Object.entries(out).map(([key, value]) => {
  return `Type ${key}: ${value.join(', ')}`
});

console.log(result);
Andy
  • 61,948
  • 13
  • 68
  • 95
-1

This is the Dynamic Solution for your problem.

let output = input.map(d => {
let k = Object.keys(d);
let v = Object.values(d)
let text = '';
for (var i in k) {
    text += `${k[i]}: ${v[i]}, `
}
text = text.substring(0, text.length - 1);
return text })
Liam
  • 27,717
  • 28
  • 128
  • 190