0

Let's say that I have this array.

const arr = [['grass', 'water'], ['fire', 'ground'], ['fairy', 'mage'], ['fighter', 'fire']];

So what I want is to concatenate arr[0] with arr[2], arr[1] with arr[3].

This has to be done trough some array method or loop, since I don't know how much of elements I will have.

Result should look like this

const arr = [['grass', 'water', 'fairy', 'mage'], ['fire', 'ground', 'fighter', 'fire']];
10
  • 1
    What have you tried so far to solve this on your own? Commented Apr 12, 2021 at 14:44
  • 1
    This example might be helpful: w3schools.com/jsref/tryit.asp?filename=tryjsref_concat Commented Apr 12, 2021 at 14:44
  • There is no dynamic way to do it, this have to be very statistic. Unless there is somehow a structure map we can fallow. Commented Apr 12, 2021 at 14:45
  • 3
    what is the pattern in which the concatenation should happen? Can you generalise it. Commented Apr 12, 2021 at 14:47
  • 1
    @mike2501 And what if you have odd no. of items like 5? Commented Apr 12, 2021 at 14:55

3 Answers 3

2

If you mod the current index with half the length of the array, then you would get corresponding index in the resultant array.

Index in original array

0 1 2 3 4 5

Index in resultant array

0 1 2 0 1 2  // After taking modulus with 3 i.e. half of the array length

Solution

  1. I've used the Nullish coalescing operator to assign the res array with empty array if the desired position is empty.

  2. Then push all the elements into this position and finally return the resultant.

NOTE: This solution only works for arrays of even length.

const arr = [
  ["grass", "water"],
  ["fire", "ground"],
  ["fairy", "mage"],
  ["fighter", "fire"],
  ["water", "ice"],
  ["ground", "rock"],
];

const result = arr.reduce(
  (r, el, i) => (
    (r[i % (arr.length / 2)] ??= []), r[i % (arr.length / 2)].push(...el), r
  ),
  []
);

console.log(result);

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

3 Comments

Yea this works, looks great but too complicated to me, since I'm beginner working on my first application.
@mike2501 No problem, you might come back to it later, when you feel comfortable.
I've been struggling to find uses of ??= at times but this seems like a good usage. The solution is good - I like it. But a bit non-idiomatic. Makes it harder for some to figure it out. I'd write out the full body for clarity like this, as it's harder to read it as an expression. You can then just add the single expression body separately in the answer just to show it off. Not sure how to keep the logic but make it easier to comprehend. Maybe a conditional operator but I really dislike those. So, good solution but a bit niche.
1

You can do something like this:

const arr = [['grass', 'water'], ['fire', 'ground'], ['fairy', 'mage'], ['fighter', 'fire']];
const newArr = [];
for (let i = 0; i <  arr.length/2; i++){
    newArr.push(arr[i].concat(arr[i + 2]));
}
console.log(newArr);

1 Comment

I just did that second, before you published it, since I noticed I haven't used .length property, yes that is true, thank you very much, it solves problem!
1

Here are few options that work for even numbered arrays.

No mutations

  1. Iterate from the start to half the array.

  2. Join the item at the current index with the one that is equal distance from the middle of the array:

    • Iteration 1:
    [0, 1, 2, 3]
     ^     ^
    
    • Iteration 2:
    [0, 1, 2, 3]
        ^     ^
    
  3. Add each of these to a new array. The original and all its members are untouched.

With a loop

function* slice(start, end, arr) {
  if (start < 0) 
    start = arr.length + start;

  if (end < 0) 
    end = arr.length + start;
    
  for (let i = start; i < end; i++) {
    yield arr[i];
  }
}

const arr = [['grass', 'water'], ['fire', 'ground'], ['fairy', 'mage'], ['fighter', 'fire']];

const middle =  arr.length / 2;

const result = Array.from(
  slice(0, middle, arr), 
  (first, i) => first.concat(arr[middle + i])
);
console.log(result);

With array methods

const arr = [['grass', 'water'], ['fire', 'ground'], ['fairy', 'mage'], ['fighter', 'fire']];

const middle =  arr.length / 2;
const result = arr
  .slice(0, middle)
  .map((first, i) => first.concat(arr[middle + i]));

console.log(result);

Using a generator

To avoid intermediate arrays from .slice() you can use a generator function and pass it through Array.from() supplying a mapping function to generate an array:

const arr = [['grass', 'water'], ['fire', 'ground'], ['fairy', 'mage'], ['fighter', 'fire']];

const middle =  arr.length / 2;
const result = arr
  .slice(0, middle)
  .map((first, i) => first.concat(arr[middle + i]));

console.log(result);

With mutations

  1. Start before the middle of the array and go backwards.

  2. Remove the last item in the array. Add its members to the item at the current index.

    • Iteration 1:
    [0, 1, 2, 3]
        ^     ^
    
    remove last: 3
    combine with: 1
    
    • Iteration 2:
    [0, 13, 2]
     ^      ^
    
    remove last: 2
    combine with: 0
    
    • End result:
    [02, 13]
    
  3. This is all done in-place. Both arr and its members are modified.

const arr = [['grass', 'water'], ['fire', 'ground'], ['fairy', 'mage'], ['fighter', 'fire']];

const middle =  arr.length / 2;
for (let i = middle - 1; i >= 0; i--) {
  const first = arr[i];
  const second = arr.pop();
  first.push(...second);
}

console.log(arr);

1 Comment

Would you please mind looking at my solution once! I would really appreciate that.

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.