0

I have an array that represents html items that can be dragged and therefore the order can be changed. Let's say before drag'n'drop event there is an array:

let oldArr = 
  [{id: 'id1'}, {id: 'id2'}, {id: 'id3'}, {id: 'id4'}, {id: 'id5'}, {id: 'id6'}]

and after dragging and reordering single item (let's say dragging item id5 to position (index) 2 the array will be:

let newArr = 
  [{id: 'id1'}, {id: 'id2'}, {id: 'id5'}, {id: 'id3'}, {id: 'id4'}, {id: 'id6'}]

How could it be decided which item was dragged to new position by comparing the old and the new aray?

Please note that if only 2 next-to-each-other items are changed, then it is impossible to decide which one of those 2 items was actually dragged - in this case it doesn't matter which one item of those two will be the result.

Axel Stone
  • 1,521
  • 4
  • 23
  • 43
  • 1
    Why can't you determine this _while_ the dragging happens, why do you need to try and determine it only afterwards from this resulting array? – CBroe Aug 01 '23 at 09:02
  • @CBroe I'm using https://github.com/react-grid-layout/react-grid-layout where the onLayoutChange callback fired when dragging the grid elements returns only the new layout but not th dragged item itself. – Axel Stone Aug 01 '23 at 09:07
  • Loop through the two arrays in parallel. When the corresponding IDs don't match, you've found the difference. – Barmar Aug 01 '23 at 09:13
  • @Barmar that's not enough. In this case I would get 3 not corresponding items, but I need to get the one that has been dragged. – Axel Stone Aug 01 '23 at 09:15
  • 1
    Find the first and last changed indexes, one of them is the moved item. Remove each of them by ID from both arrays and check if the rest of the array is the same. Whichever one you remove that leaves the rest equal is the one that was moved. – Barmar Aug 01 '23 at 09:24
  • E.g. 1, 2, 3, 4 => 3, 1, 2, 4. index1 = 0 contains id 3, index2 = 2 contains id 2. When we remove 3 from both arrays, it's 1, 2, 4 == 1, 2, 4, so 3 was dragged. If you remove 2 from both arrays yuo get 1, 3, 4 != 3, 1, 4, so 2 wasn't dragged. – Barmar Aug 01 '23 at 09:26
  • 1
    How about determining the neighbors of each element in `oldArr` ... `{ "id1": "-|id2", "id2": "id1|id3", "id3": "id2|id4", "id4": "id3|id5", "id5": "id4|id6", "id6": "id5|-" }` ... and then checking for element(s) that have changed BOTH "neighbors" in `newArr`? – PeterKA Aug 01 '23 at 14:26

1 Answers1

1

Use elements before and after a target element (neighbors) to determine which element(s) has(have) moved. You can refine the logic to more closely suit your situation:

const
      oldArr = [{id: 'id1'}, {id: 'id2'}, {id: 'id3'}, {id: 'id4'}, {id: 'id5'}, {id: 'id6'}],
      newArr = [{id: 'id1'}, {id: 'id2'}, {id: 'id5'}, {id: 'id3'}, {id: 'id4'}, {id: 'id6'}],
      
      //Now get old neighbors (oldn) and new neighbors (newn)
      oldn = oldArr.reduce((o,{id},i,a) => ({...o, [id]:[(i === 0) ? '-' : a[i-1].id, (i === a.length - 1) ? '-' : a[i+1].id]}), {}),
      newn = newArr.reduce((o,{id},i,a) => ({...o, [id]:[(i === 0) ? '-' : a[i-1].id, (i === a.length - 1) ? '-' : a[i+1].id]}), {}),
      
      //Now check which has changed both neighbors. The logic can be refined.
      whichmoved = oldArr.filter(({id}) => oldn[id].every(n => !newn[id].includes(n)));

console.log( oldn, newn, '\n\n\nMoved:\n', whichmoved );
PeterKA
  • 24,158
  • 5
  • 26
  • 48