First time here? Check out the FAQ!

How can I store elements inside an array in ascending order?

+1 vote
I can't think of a way to do that..


Little example:

array1: (0.2 0.8 1.0)

now I store 0.1 on index1 (previously 0.8)

(0.2 0.1 1.0)

but I want it to be:

(0.1 0.2 1.0)


also another array should be ordered the same way (but not ascending, just following the ordering of the first):

array1 like above: (0.2 0.8 1.0)

array2: (a b c)

should turn into:

array1: (0.1 0.2 1.0)

array2: (b a c)


and all of that using capyTalk, I want to do that while the sound is running.

I hope that makes sense? :)
asked Jul 1, 2015 in Capytalk & Smalltalk by kymaguy (Virtuoso) (10,580 points)
What is the end goal? In other words, what will be in the Arrays and how will you be using them?  Thanks!
I want to use the arrays for the InputOutputCharacteristic, the InValues (array1) have to be in ascending order and I need the out values (array2) move to the same place in order to make it work properly. there will be values in the range of -1,1 only.
Since you're entering the fader values from the VCS, could you not just enter them in the correct order in the first place?
That's the way I'm doing it now and I think that's the best way to go efficiently unless I'm porting the whole thing into a Tool. Thank you for your time and effort!!!

1 Answer

+1 vote
Best answer

Since Capytalk is a functional language without loop structures, you have to think of sorting in a different way than you would in a language like C or Smalltalk.  Each element in the sorted Array is going to be a Capytalk expression describing which EventValues have values less than the value in this slot, and which EventValues have a value greater than the one in this slot.

If you write it all out explicitly, then each expression in the Array gets longer than the one in the previous position. This can get messy quickly, so here's some Smalltalk to construct the Array of Capytalk expressions:

| eventValues sortedArray min max leftIndex rightIndex infinity minusInfinity prevMin prevMax |

eventValues := {!P copies: 5}.
sortedArray := Array new: eventValues size.

"Set min and max to values that can never be found in your eventValues."
infinity := 8000.
minusInfinity := -8000.

prevMin := minusInfinity.
prevMax := infinity.

"Construct an expression that puts the minimum at the leftmost index and maximum at the rightmost index. Keep track of min and max as you move the leftIndex to the right and rightIndex to the left until you meet in the middle."

leftIndex := 1.
rightIndex := eventValues size.

[leftIndex <= rightIndex] whileTrue: [
    min := infinity.
    max := minusInfinity.

    1 to: eventValues size do: [ :i | | p |
        p := eventValues at: i.

        "If p has already been sorted, use infinity or minusInfinity in its place, effectively removing it from the computation of the min or max."
         min := ((p gt: prevMin) true: (p) false: (infinity)) vmin: min.
        max := ((p lt: prevMax) true: (p) false: (minusInfinity)) vmax: max].

    sortedArray at: leftIndex put: min.
    sortedArray at: rightIndex put: max.

    prevMin := min.
    prevMax := max.

    leftIndex := leftIndex + 1.
    rightIndex := rightIndex - 1].    

And here's a Sound that uses this code to create a sorted array of ascending pitches for an AnalogSequencer. It captures !KeyNumbers using sampleAndHold on !KeyDown (you can use the Fake Keyboard from the Tools menu to enter them if you don't have a keyboard).  No matter what order you play the pitches, the sequencer plays them in sorted or ascending order. 

The first Sound displays the captured values as !Ps and the sorted values as !Qs.  In the second Sound, the Smalltalk to create the sorting Capytalk Array is pasted directly into the KeyPitches parameter field.

answered Jul 2, 2015 by ssc (Savant) (124,560 points)
selected Jul 2, 2015 by kymaguy
WOW! I knew there's a way but constructing CapyTalk arrays using smalltalk is kind of tricky - truly amazing!
The only thing is I still haven't sorted a second array according to the first.
To stick with your example: Is there a way to capture and sort !KeyVelocity according to !KeyPitch?
Thanks SSC for a really instructive answer and example!

I have previously used a Sort Block to organise an array of filenames from shortest file duration to longest. The snippet you posted, is an expanded version of such a SortBlock, right?
In retrospect, a better name for the final variable might have been selfSortingArray (instead of sortedArray).  This snippet of code is not doing any sorting; it's constructing an array of Capytalk expressions that return values in sorted, ascending order.
Cristian is right; a sortBlock would be the natural way to accomplish the sorting of one Array according to the order of another.  I still think you would be better off using a Tool to do this (that way, you can do it in Smalltalk).
If i read it correct this is a smalltalk constructor to create a sorting mechanism with Capytalk expressions: vmin and vmax and a upfront known number of hot values? (5 in your case). It would be a solution for this question:
I am not in front of my Kyma system today but i will try asap.. it would make "realtime" composing so much easier... sorting notes in realtime and chords in realtime in kyma is still a goal i want to achieve without writing dedicated  vmin: vmax: expressions...


p.s.: I found one of my sketches... so far i did it this way for a note array of 4 !HotValues(in this case !Voice1 to !Voice4):

"sorting the notes of the chords from lowest to highest"

lowest := ((!Voice1 vmin: !Voice2) vmin: !Voice3) vmin: !Voice4.
highest := ((!Voice1 vmax: !Voice2) vmax: !Voice3) vmax: !Voice4.

middleBottom :=
(!Voice4 eq: lowest) of: (Array
       with: ((!Voice3 eq: lowest) of: (Array
                with: ((!Voice2 eq: lowest) of: #(
                           {(!Voice2 vmin: !Voice3) vmin: !Voice4}
                           {(!Voice1 vmin: !Voice3) vmin: !Voice4}))
                 with: ((!Voice1 vmin: !Voice2) vmin: !Voice4)))
       with: ((!Voice1 vmin: !Voice2) vmin: !Voice3)
middleTop :=
(!Voice4 eq: highest) of: (Array
       with: ((!Voice3 eq: highest) of: (Array
                with: ((!Voice2 eq: highest) of: #(
                           {(!Voice2 vmax: !Voice3) vmax: !Voice4}
                           {(!Voice1 vmax: !Voice3) vmax: !Voice4} ))
                 with: ((!Voice1 vmax: !Voice2) vmax: !Voice4)))
       with: ((!Voice1 vmax: !Voice2) vmax: !Voice3)

chordArraySorted:= Array with: lowest  with: middleBottom  with: middleTop with: highest.
That's great Christian! I think the SSC approach is a solution for the question in the forum you mentioned.