Splitting a list of ints, using a special number as a "separator"

I’m trying to split an incoming list of numbers to fill an ArrayList. Each new chopped IntList would have a different size, and on the incoming -unchopped- list i can use -1 as the separator.

I’m having problems to parse correctly the incoming list and distribute the slices in the ArrayList, as it looks like with my terrible code just the last slice is filling the whole ArrayList. I’ve been trying to achieve the result i’d expect for hours, but i can’t find the solution for myself…

Is anyone familiar with this kind of “list-chopping” operations and can give me a hand?

(The code i’m attaching is a stripped-down version… on my final application the list to be chopped will be received through OSC… and that would explain why the first number in the list is the length of the list. As far as i know there’s no way to retrieve the size of an OSC message, so i managed to add the size on the first position on my OSC sending Max/MSP patch)

ArrayList <IntList> Scales = new ArrayList <IntList>();
IntList oscList=new IntList(16,-1,0,1,2,3,-1,10,20,30,40,-1,100,200,300,400,500);
int oscListSize;

void setup(){
}

void draw(){
}

void keyPressed() {
   Scales.clear();
      IntList tmp=new IntList(); //temporary list
      int counter=0;
      oscListSize = oscList.get(0); //the first value of oscList is the size of the list itself
        for(int i=1;i<oscListSize+1;i++){
          int num=oscList.get(i);
          if(num==-1){ //-1 is the "separator" between lists
            Scales.add(tmp); //add the tmp intlist to the Scales arraylist
            tmp.clear(); //afterwards, clear tmp
            counter=counter+1;         
          }
          else{
            tmp.append(num); //if num is different to -1, add it to the tmp list     
          }         
        }
     println(Scales); //print the result (which is not the expected one)     
  }

IntList got a “hidden” method getSubset() which is very useful for splitting:

As you can see from its source code above, the method returns a new IntList.

1 Like

Also, the list has to end with -1 OR you flush the ending in your target list

1 Like

Not sure if this works

For loop over it first (sorry, this was not the reason)


SOLVED —

your program was correct, but you need to make a copy here: Scales.add(tmp.copy());

to get a new object or whatever

(also I appended -1 as mentioned)

and you can use size() here: for (int i=0; i<oscList.size();

Chrisir

// source 
IntList oscList=new IntList(16, -1, 0, 1, 2, 3, -1, 10, 20, 30, 40, -1, 100, 200, 300, 400, 500, -1);

//destiny
ArrayList <IntList> Scales = new ArrayList <IntList>(); ....

void setup() {
  size(330, 330);
}

void draw() {
  //
}

// ------------------------------------------------------------------------------

void keyPressed() {
  //
  Scales.clear();
  IntList tmp=new IntList(); //temporary list
  int counter=0;

  for (int i=0; i<oscList.size(); i++) {
    int num=oscList.get(i);
    if (num==-1) { //-1 is the "separator" between lists
      Scales.add(tmp.copy()); //add the tmp intlist to the Scales arraylist // COPY 
      tmp.clear(); //afterwards, clear tmp
      counter=counter+1;
    } else {
      tmp.append(num); //if num is different to -1, add it to the tmp list
    }
  }
  println(Scales); //print the result (which is not the expected one)
  println("---"); 
  for (IntList intl : Scales) {
    println(intl);
  }
}
//

2 Likes

This sketch will split an IntList into multiple lists on a given value. It ignores the first element in the list because this is not a value but rather the number of elements in the ocs message. The algorithm is ‘stable’ in that it does not alter the order of the elements within the original list.

You should be able to adapt this to suit your own sketch. :smile:

IntList oscList = new IntList(16, -1, 0, 1, 2, 3, -1, 10, 20, 30, 40, -1, 100, 200, 300, 400, 500);
ArrayList<IntList> scales;

void setup() {
  size(600, 400);
  scales = splitter(oscList, -1);
  for (IntList i : scales)
    println(i);
}

ArrayList<IntList> splitter(IntList list, int splitOn) {
  ArrayList<IntList> lists = new ArrayList<IntList>();
  IntList temp = new IntList();
  // ignore element containing list size
  for (int idx = 1, len = list.size(); idx < len; idx++) {
    int element = list.get(idx);
    if (element == splitOn) {
      if (temp.size() > 0) {
        lists.add(temp);
        temp = new IntList();
      }
    } else {
      temp.append(element);
    }
  }
  // Add any list left over
  if (temp.size() > 0)
    lists.add(temp);
  return lists;
}

2 Likes

I see.

Instead of using …copy() as I did, you use temp = new IntList(); so that we have a new object and do not overwrite the old one

(otherwise the memory address stays the same and the object in Scales at this position gets overwritten)

1 Like

@chrisir yes I didn’t look closely at your answer which does the job just as well as my effort. :smile:

2 Likes

Wow! thanks for your unvaluable help @Chrisir and @quark!
Both solutions do the job, and now i can go on developing my sketch… yeehaa!!!

This is going to be part of an spectrogram generator which i’ve been working with for a couple of years, and which create images that “sound good” when IFFT’d:

With this help of yours, now i will be able to define a different chord per bar, which was something lacking until now!

Thank you very much!
Please drop a line if you ever come around Barcelona and i’ll be glad to invite you to some beers!!!

3 Likes

Well, I did a 3rd solution using IntList’s method getSubset(); plus its methods removeValue() & copy():

/**
 * Split IntList by a Separator Value (v1.0.0)
 * GoToLoop (2022/Aug/24)
 *
 * https://Discourse.Processing.org/t/
 * splitting-a-list-of-ints-using-a-special-number-as-a-separator/38471/9
 */

static final IntList OSC_VALS = new IntList(
  16, -1, // list size
  0, 1, 2, 3, -1, 
  10, 20, 30, 40, -1, 
  100, 200, 300, 400, 500
  );

static final int SEPARATOR = -1;

import java.util.Collection;
Collection<IntList> scales;

void setup() {
  // Skipping 1st & 2nd elements containing list size and its separator:
  final IntList oscVals = OSC_VALS.getSubset(2);

  scales = splitter(oscVals, SEPARATOR);
  for (final IntList list : scales)  println(list);

  exit();
}

static final Collection<IntList> splitter(final IntList list, final int sep) {
  // Result collection of split subsets from recieved IntList:
  final Collection<IntList> splits = new ArrayList<IntList>();

  // Cloning received IntList so we're free to use removeValue() on it:
  final IntList clone = list.copy();

  // Iterator prevIdx is previous index where separator value was found:
  for (int idx, prevIdx = 0; prevIdx >= 0; prevIdx = idx) {
    // Remove & get index of 1st found separator value. Otherwise gets -1:
    idx = clone.removeValue(sep);

    // Add() a new IntList subset to splits starting from index prevIdx:
    if (idx >= 0)  splits.add(clone.getSubset(prevIdx, idx - prevIdx));
    else           splits.add(clone.getSubset(prevIdx)); // no separator found
  }

  return splits;
}
3 Likes

Yeah! thanks @GoToLoop!

I never imagined there could be so many ways to face this problem… i’m ashamed of how much knowledge i still need to glimpse…

Certainly, the getSubset() method of IntList is a powerful tool.
I’m sure i’m going to use it a lot on the forthcoming weeks… i have many lists to process!!!

Again, i’d be pleased to thank you for your help if you ever come around Catalonia… please drop a line and we’ll be happy to host you at our beautiful place at Playmodes headquarters!

1 Like

Thx for the invitation but I’m very far away from there in Brazil. :sunny:

4 Likes