Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question How to find tuples in a list an merge them?

Discussion in 'Scripting' started by moEJoe82, Jan 5, 2023.

  1. moEJoe82

    moEJoe82

    Joined:
    Jun 14, 2017
    Posts:
    10
    I have a list of Game Objects ID, for example, {ID1, ID2, ID3, ID3, ID3, ID2, ID2, ID1, ID2, ID2, ID4}

    I need to keep looping through the list and merge Game Objects with similar ID, like this:

    First itiration: {ID(1+1), ID2, ID(2+2), ID(2+2), ID3, ID(3+3), ID4} => {ID2, ID2, ID4, ID4, ID3, ID6, ID4}
    Second itiration: {ID(2+2), ID(4+4), ID3, ID6, ID4} => {ID4, ID8, ID3, ID6, ID4}
    Third itiration: {ID(4+4), ID8, , ID6, ID3} => {ID8, ID8, ID6, ID3}
    Fourth itiration: {ID(8+8), ID6, ID3} => {ID16, ID6, ID3}

    I have been stuck in this for several hours without any clue! any help is really appreciated!
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,949
    Does it have to be in iterations? If not, just throw them all in a set, which makes then unique, then iterate the set and for each thing in the set, iterate your original collection and remove it.
     
    chemicalcrux likes this.
  3. moEJoe82

    moEJoe82

    Joined:
    Jun 14, 2017
    Posts:
    10
    Thanks for the answer, but I'm afraid that doesn't solve my problem, as it will merge the first itiration
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,949
    Well the first part of my solution still works to get you a list of only what is unique.

    From your iteration list I'm not able to easily discern a pattern, but perhaps once you know the unique objects you can decide how to proceed?

    Or else perhaps just describe your intentions more generically?
     
  5. chemicalcrux

    chemicalcrux

    Joined:
    Mar 16, 2017
    Posts:
    717
    This sounds like a counting sort! We can just modify the algorithm a bit to combine the copies together.
    1. Count how many copies of each number we have. Maybe use a dictionary?
    2. Create a new list with one copy of each number (multiplied by the count)
    Probably not as-fast-as-possible, but oh well.

    Now, if you need to do something more complex -- e.g. if each element in the list is more than just a number, and has to have some logic run on it -- then that'll take a bit more work.
     
  6. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,571
    Uhm, I'm not sure how that applies to "IDs" as an ID is usually an identification number. Since you seem to apply arithmetic on them (so you add two of the same numbers together). Or why does grouping two objects with the ID 3 gives an object with ID6?

    To me it looks like you want to combine entries in pairs if they have the same value. The simplest and straight forward solution is to use a source list and a target list where you put the "combined" objects and just use a nested for loop to carry out a single iteration

    You made the question deliberately abstract as we don't know what type your List actually contains and where that ID comes from or where it is stored. If it's a list of gameobjects, you would probably have a component on them that holds the ID? If that's the case it would make more sense to use a List of those components. So lets assume each of those gameobjects have a script on them called "ID" and it has a field called "val" that actually represents the value we care about. So it looks like this:

    Code (CSharp):
    1.  
    2. public bool Combine(List<ID> aSource, List<ID> aTarget)
    3. {
    4.     aTarget.Clear();
    5.     bool hasCombinations = false;
    6.     while (aSource.Count > 0)
    7.     {
    8.         ID obj = aSource[0];
    9.         for(int n = 1; n < aSource.Count; n++)
    10.         {
    11.             if (obj.val == aSource[n].val)
    12.             {
    13.                 // found a pair, "combine" them and store the combine object in obj
    14.                 obj = CombineTwoObjs(obj, aSource[n]);
    15.                 // remember that we actually combined something during this method call
    16.                 hasCombinations = true;
    17.                 // remove the second object from the source list
    18.                 aSource.RemoveAt(n)
    19.                 // we're done, exit inner loop and continue with outer loop
    20.                 break;
    21.             }
    22.         }
    23.         // add current obj to the target list. This is either the object from the source list
    24.         // or our new "combined" object.
    25.         aTarget.Add(obj);
    26.         // remove the first object from source as we are done with it.
    27.         aSource.RemoveAt(0);
    28.     }
    29.     return hasCombinations;
    30. }
    You can call this method repeatedly with alternating lists until the method would return false in which case there were no new combinations as we went through the list

    So something like that:
    Code (CSharp):
    1.  
    2. public List<ID> Iterate(List<ID> aObjs)
    3. {
    4.     List<ID> tmp = new List<ID>(aObjs);
    5.     List<ID> tmp2 = new List<ID>();
    6.     while (true)
    7.     {
    8.         if (!Combine(tmp, tmp2))
    9.             return tmp2;
    10.         if (!Combine(tmp2, tmp))
    11.             return tmp;
    12.     }
    13. }
    This should return a new list with the "combined" objects and it terminates once it can no longer combine them. How you combine them is up to you. The method "CombineTwoObjs" needs to be provided by you. it takes two ID instances as arguments and needs to return the combined object.
     
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,571
    I'd like to add that your example iterations doesn't seem to make much sense, especially the "order" which each iteration produces. You as a human are tempted to "combine" the same IDs that are next to each other. However a computer generally just iterates over the list to find the first matching pair. So given your initial list
    Code (CSharp):
    1. {ID1, ID2, ID3, ID3, ID3, ID2, ID2, ID1, ID2, ID2, ID4}
    After each Combine call you would get those intermediate lists

    Code (CSharp):
    1. {ID1, ID2, ID3, ID3, ID3, ID2, ID2, ID1, ID2, ID2, ID4}
    2. {ID2, ID4, ID6, ID3, ID4, ID2, ID4}
    3. {ID4, ID8, ID6, ID3, ID4}
    4. {ID8, ID8, ID6, ID3}
    5. {ID16, ID6, ID3}
    So after the first step, the first ID2 is the two ID1s combined, the ID4 is the first ID2 and the second ID2 combined, and so on. So the first iteration would combine the indices (0,7), (1,5), (2,3), 4, (6,8), 9, 10
    In the second iteration you get the pairs (0,5), (1,4), 2, 3, 6
    After that (0,4), 1, 2, 3
    and finally (0,1), 2, 3