1

I have an array that is defined like this:

const arr = [
  {
    status: 'status1',
    count: 2,
    elements: [
      {
        id: '1',
      },
      {
        id: '2',
      },
    ],
  },
  {
    status: 'status2',
    count: 1,
    elements: [
      {
        id: '3',
      },
    ],
  },
  {
    status: 'status3',
    count: 1,
    elements: [
      {
        id: '4',
      },
    ],
  },
];

The array is dynamic, but I know the status field and the id inside the elements. What I am trying to achieve is a new array, that contains all the same items, but looks like this instead:

const arr = [
  {
    status: 'status1',
    count: 1,
    elements: [
      {
        id: '1',
      },
    ],
  },
  {
    status: 'status2',
    count: 2,
    elements: [
      {
        id: '2',
      },
      {
        id: '3',
      },
    ],
  },
  {
    status: 'status3',
    count: 1,
    elements: [
      {
        id: '4',
      },
    ],
  },
];

In other words, if status === status1, remove element with id === 2, set count to the length of elements array (or decrease by 1), take the element that has id === 2 and put it into elements array that has status === status2, set total count to the length of elements array .

I am not all that strong with iterating through nested elements and manipulating the array in these ways, but simpler concepts with array.filter/map etc seems okay, but I cannot wrap my head around all of this. :P

I would prefer to use vanilla JS, if possible. But I do have access to lodash if it makes things a lot easier.


Edit: When I mean vanilla JS, I refer to not using a ton of external libraries, but ES6 is what I use at this project.

My try consists of simply trying to filter arr on status, and then again on my id. Then I know what item I want to move. But it kind of stops there, and I also believe that it could be much more efficient:

const itemToMove = arr.filter(e => e.status === "status1")[0].elements.filter(e => e.id ==='2' )

I am not sure how to best proceed after this, thus asking for help.

zhulien
  • 5,145
  • 3
  • 22
  • 36
dtd
  • 79
  • 11
  • at least, you could add your try ... – Nina Scholz Mar 31 '21 at 08:27
  • Where is the code that shows that you have tried to solve this yourself which we can improve upon? Also, when you say vanilla JS which version of ECMAS script do you consider vanilla? – DanteTheSmith Mar 31 '21 at 08:29
  • I have edited my answer, but as I am not sure how to solve it, and I also belive that my filter().filter() could be much improved, I did not want to include it. – dtd Mar 31 '21 at 08:39

1 Answers1

2

You could find the source and target objects and splice the element.

const
    move = (data, from, to, id) => {
        const
            find = value => ({ status }) => status === value,
            source = data.find(find(from)),
            target = data.find(find(to)),
            index = source.elements.findIndex(o => o.id === id);
            
        if (index === -1) return;
        
        target.elements.push(...source.elements.splice(index, 1));
        source.count--;
        target.count++;
    },
    array = [{ status: 'status1', count: 2, elements: [{ id: '1' }, { id: '2' }] }, { status: 'status2', count: 1, elements: [{ id: '3' }] }, { status: 'status3', count: 1, elements: [{ id: '4' }] }];
   

move(array, 'status1', 'status2', '2');
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Thank you, this does exactly what I asked for. It does also edit the original array, and my usecase cannot modify the original array, but I belive I can find a solution for that :) Thank you! – dtd Mar 31 '21 at 11:19