0

I have the following arrays:

array_order = [ 'SiteA', 'SiteC', 'SiteB' ]

string_array = [
                [ 'Site C', 'StringC1_' ] ,
                [ 'Site A', 'StringA1_' ] ,
                [ 'Site C', 'StringC2_' ] ,
                [ 'Site B', 'StringB1_' ] ,
                [ 'Site B', 'StringB2_' ] ,
                [ 'Site B', 'StringC3_' ] ,
                [ 'Site B', 'StringA2_' ]
               ]

I want to group the strings by site and output them as a concatenated string in order of array_order, so something like this:

output = [ 'StringA1_StringA2_', 'StringC1_StringC2_StringC3_', 'StringB1_StringB2_' ]

The concatenation order doesn't matter, for example 'StringA1StringA2' is just as fine as 'StringA2StringA1' so I don't need to worry about sorting them.

I was initially thinking I could convert string_array to an object, then somehow concatenate by group, then map it something like array_order.map(key => obj[key]) but I am struggling with making an object to be iterated and concatenated.

3
  • Is StringC3_ supposed to be under "Site B"?, as you grouping by the letter C found in the string or by the "Site"? Commented Jun 25, 2021 at 11:28
  • In array_order you do not have space in group name, but in string_array you do Commented Jun 25, 2021 at 11:34
  • 1
    This entry seem to be wrong: [ 'Site B', 'StringC3_' ] Commented Jun 25, 2021 at 11:34

5 Answers 5

2

Yet another way:

const siteOrder = ['Site A', 'Site C', 'Site B']

const strings = [
  ['Site C', 'StringC1_'],
  ['Site A', 'StringA1_'],
  ['Site C', 'StringC2_'],
  ['Site B', 'StringB1_'],
  ['Site B', 'StringB2_'],
  ['Site B', 'StringC3_'],
  ['Site B', 'StringA2_'],
]

const result = siteOrder.reduce((acc, site) => {
  acc[site] = ''
  return acc
}, {})

strings.forEach((siteString) => {
  const [site, string] = siteString
  result[site] += string
})
console.log({ result })

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

1 Comment

@RajdeepDebnath, I think mine is cleaner, but this is a good answer too : )
2

Just use simple map and reduce

array = ["Site A", "Site C", "Site B", "Site X"];

data = [
  ["Site C", "StringC1_"],
  ["Site A", "StringA1_"],
  ["Site C", "StringC2_"],
  ["Site B", "StringB1_"],
  ["Site B", "StringB2_"],
  ["Site B", "StringB3_"],
  ["Site B", "StringB4_"],
];

const output = array.map(e =>
  data.reduce((a, b) => (a += b[0] === e ? b[1] : ""), "")
);

console.log(output);

1 Comment

This one is amazing mate :)
1

You can use Array.reduce on string_array to build your output array, we'll find the correct output index from running Array.findIndex on the array_order input array.

If we don't find the item, we'll skip adding it to the output:

array_order = [ 'SiteA', 'SiteX', 'SiteC', 'SiteB']

string_array = [
                [ 'SiteC', 'StringC1_' ] ,
                [ 'SiteA', 'StringA1_' ] ,
                [ 'SiteC', 'StringC2_' ] ,
                [ 'SiteB', 'StringB1_' ] ,
                [ 'SiteB', 'StringB2_' ] ,
                [ 'SiteC', 'StringC3_' ] ,
                [ 'SiteA', 'StringA2_' ]
               ]
               
 let result = string_array.reduce((acc, [site, value], arr) => { 
      let index = array_order.findIndex(el => el === site);
      if (index >= 0) { 
         acc[index] = (acc[index] || "") + value;
      }
      return acc;
 }, array_order.map(el => ""))
 
 
 console.log('Result:', result);

And another way of doing this with Array.map, Array.filter and Array.join:

array_order = [ 'SiteA', 'SiteX', 'SiteC', 'SiteB']

string_array = [
                [ 'SiteC', 'StringC1_' ] ,
                [ 'SiteA', 'StringA1_' ] ,
                [ 'SiteC', 'StringC2_' ] ,
                [ 'SiteB', 'StringB1_' ] ,
                [ 'SiteB', 'StringB2_' ] ,
                [ 'SiteC', 'StringC3_' ] ,
                [ 'SiteA', 'StringA2_' ]
               ]
     
let result = array_order
 .map(el => string_array.filter(([site, val]) => site === el)
 .map(([site, val]) => val)
 .join(""));
 
console.log("Result:",result);

2 Comments

how would I edit this to have a null value if there is are no matches, rather than skip it? eg Result: [ "StringA1_StringA2_", "", "StringB1_StringB2_"]
I've updated to leave an empty string if no matches are found.
1

First yo need to group the items, then you can map each group concatenating the strings:

const grouped_arrays = string_array.reduce((result, entry) => {
  const [groupName, value] = entry;
  result[groupName] = result[groupName] || [];
  result[groupName].push(value);
  return result;
}, {});

const result = array_order.map(groupName => {
  return (grouped_arrays[groupName] || []).join('');
});

Also note that your array_order group names do not have space: 'Site C' !== 'SiteC'

1 Comment

thanks, I made a couple of typos in the question. in real life, Site C is SiteC. will try shortly.
1

You can use reduce for this

array_order = [ 'Site A', 'Site C', 'Site B' ]

string_array = [
                [ 'Site C', 'StringC1_' ] ,
                [ 'Site A', 'StringA1_' ] ,
                [ 'Site C', 'StringC2_' ] ,
                [ 'Site B', 'StringB1_' ] ,
                [ 'Site B', 'StringB2_' ] ,
                [ 'Site B', 'StringC3_' ] ,
                [ 'Site B', 'StringA2_' ]
               ]
               
let result = [...string_array.reduce((acc,[k,v]) => {
                    acc.has(k)? acc.set(k, acc.get(k)+v) : acc.set(k,v);
                    return acc;
                 }
               , new Map())]
      .sort((a,b) => array_order.indexOf(a[0])-array_order.indexOf(b[0]))
      .map(i => i[1])

console.log(result);

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.