Support

If you have a problem or need to report a bug please email : support@dsprobotics.com

There are 3 sections to this support area:

DOWNLOADS: access to product manuals, support files and drivers

HELP & INFORMATION: tutorials and example files for learning or finding pre-made modules for your projects

USER FORUMS: meet with other users and exchange ideas, you can also get help and assistance here

NEW REGISTRATIONS - please contact us if you wish to register on the forum

Users are reminded of the forum rules they sign up to which prohibits any activity that violates any laws including posting material covered by copyright

Ruby sort method on [x1,y1] [x2,y2] ... [xn,yn] data

For general discussion related FlowStone

Ruby sort method on [x1,y1] [x2,y2] ... [xn,yn] data

Postby steph_tsf » Sun Feb 02, 2020 8:12 pm

How to take advantage of Ruby sort methods applied on simple data (actually non-hash data) consisting of a value table organized this way : [x1,y1] [x2,y2] ... [xn,yn] ?

In the application, the [x,y] table gets maintained, storing the various frequencies (Hz) and attenuation (dB) the user asked to play. Each time the user requests a new frequency/attenuation couple, such couple gets played as audio (blue schematic) by Flowstone, such table gets updated by a << [x,y] Ruby append instruction, and then, comes the difficulty I am facing : a derivative of such table needs to get generated, this time sorted by frequency (lowest frequency first). The sorting algorithm is not allowed to consume a lot of CPU%, as I don't want each frequency/attenuation change, to cause some audio glitch or DS or ASIO buffer malfunction.

I am sorry, I miserably failed in converting the [x,y] array into a hash, then sorting the hash, then converting the hash back into a [x,y] array. As consequence, I am currently relying on the following awful "hand-made" code :

Code: Select all
# ###############  generate @sortFLarray, basing on @FLarray data
   
# generate @tmparray, for it to contain rounded @F values along with untouched @dB values
# the rounding is required by the stupid sorting loop (NEED TO IMPROVE THIS)

@FL_len = @FLarray.length
@tmparray = []
n=0                # FLarray index
while n <= @FL_len-1
   @F = (@FLarray[n][0]).round
   @dB = (@FLarray[n][1])
   @tmparray << [@F,@dB]
   n=n+1
end   # while n
   
@sortFLarray=[]   
@sortFLarray=@tmparray         # @sortFLarray now contains integer frequencies
          
#generate @tmparray, for it to contain data, sorted by @F

@tmparray=[]
@FL_len = @sortFLarray.length   
   
n=0                # @sortFLarray index
val = 0
while (val <=24000)         # this is a stupid load for the computer
   while n <= @FL_len-1
      @F = @sortFLarray[n][0]
      if @F == val then
      @dB = @sortFLarray[n][1]         
      @tmparray << [@F,@dB]   # append data to @tmparray
      end #if
   n=n+1
   end # while n
val=val+1
n=0
end # while val

@sortFLarray=[]
@sortFLarray=@tmparray   
   
# ###############   

Your kind help will allow people like me to quickly take advantage of the elegant built-in Ruby arrays and hash manipulating instructions. It will be funny, comparing my "by hand-made" code, with the few elegant Ruby instructions that are actually required. I am curious to discover the CPU% advantage that the native Ruby sorting instructions can bring.
steph_tsf
 
Posts: 249
Joined: Sun Aug 15, 2010 10:26 pm

Re: Ruby sort method on [x1,y1] [x2,y2] ... [xn,yn] data

Postby trogluddite » Sun Feb 02, 2020 9:40 pm

What you need is the Ruby Array 'sort' method. By default, this sorts an Array by comparing pairs of elements using their '<=>' operator (which returns -1 for less, 0 for equal, +1 for greater, or nil for "can't be compared"). However, 'sort' will also take a code-block which defines how to sort the items. The code block is passed each pair of items, and should return -1, 0, or +1 to indicate their order. For example:
Code: Select all
sorted_by_freq = @FLarray.sort{|a, b| a[0] <=> b[0]}
sorted_by_gain = @FLarray.sort{|a, b| a[1] <=> b[1]}


Even more compact is the 'sort_by' method, where the block just has to say which attribute of an element should be used for comparison with '<=>':
Code: Select all
sorted_by_freq = @FLarray.sort_by{|elem| elem[0]}
sorted_by_gain = @FLarray.sort_by{|elem| elem[1]}


In this case, I don't think it would make a lot of difference which you use. The 'sort' method has the advantage that you can sort things where the '<=>' comparison isn't suitable (e.g. case-insensitive string sorting using the 'casecmp' method), or sort in reverse easily by switching the comparison around.

The 'sort_by' method has the advantage that it uses a technique which only ever calls the block once for each element, so is more efficient when extracting the compared value is expensive (e.g. if it requires querying an externally stored database). However, when extracting the value is easy, it may be no better, or even less efficient than 'sort'.

Both methods also have a "bang!" version; i.e. 'sort!' and 'sort_by!'. These work very much the same, but they don't return a new Array, they swap elements around in the original Array to do the sorting. The exclamation mark is a convention in Ruby meaning "this method may have unintended side-effects" - in this case, that changing the original Array means that its previous state is lost forever and all existing references will see the new order. A lot of Ruby's Array methods follow the same pattern of "bang!" (change the original) and "non-bang" (make a new Array) versions.

It's well worth getting to know how to use these methods which take code-block, as they do result in some very compact and efficient code. For example, to do the rounding that you showed in your code takes only this:
Code: Select all
# Returns an Array of [rounded_frequency, gain] elements.
rounded_freq = @FLarray.map{|elem| [elem[0].round, elem[1]]}

# Or even, using the fact that a code block can automatically split apart nested arrays...
rounded_freq = @FLarray.map{|freq, gain| [freq.round, gain]}
All schematics/modules I post are free for all to use - but a credit is always polite!
Don't stagnate, mutate to create!
User avatar
trogluddite
 
Posts: 1730
Joined: Fri Oct 22, 2010 12:46 am
Location: Yorkshire, UK

Re: Ruby sort method on [x1,y1] [x2,y2] ... [xn,yn] data

Postby steph_tsf » Sun Feb 02, 2020 10:30 pm

trogluddite, please tell how I could thank you enough
steph_tsf
 
Posts: 249
Joined: Sun Aug 15, 2010 10:26 pm

Re: Ruby sort method on [x1,y1] [x2,y2] ... [xn,yn] data

Postby trogluddite » Mon Feb 03, 2020 12:45 am

steph_tsf wrote:trogluddite, please tell how I could thank you enough

You're welcome. Just seeing that the modules and tips that I post are useful and being used to make funky new things is all the thanks I need! :D
All schematics/modules I post are free for all to use - but a credit is always polite!
Don't stagnate, mutate to create!
User avatar
trogluddite
 
Posts: 1730
Joined: Fri Oct 22, 2010 12:46 am
Location: Yorkshire, UK


Return to General

Who is online

Users browsing this forum: No registered users and 96 guests