Passing array's element values to lowest or highest functions in pine script - arrays

I am trying to pass dynamic values to lowest and highest built-in functions in pine script from arrays. Below is the code
int[] pArray = array.new_int(0)
pArray is populated with int elements. Here is the code below that works.
fromInd = array.min(pArray)
lowest = ta.lowest(MACDHist,array.get(pArray,0))
Debug = label.new(bar_index+1, close, 'pArray: ' + str.tostring(pArray) + str.tostring(fromInd))
The output of above code on the chart is
pArray: [2, 15, 40]2
2 is the 0th index value of pArray that is printed outside of the array in the end. However when I change the label to output 'lowest' value (shown below) nothing prints to chart but everything compiles well with no errors or warnings.
Debug = label.new(bar_index+1, close, 'pArray: ' + str.tostring(pArray) + str.tostring(lowest))
The output of 'array.get(id, index)' is series int because pArray is initialized to int. I also typecasted the 'array.get(id, index)' argument by enclosing it with 'int()' but nothing is working for the last line code except when hard coded.
'ta.lowest(source, length)' accepts series int arguments for length and it can also accept dynamic lengths as shown by tradingview https://www.tradingview.com/blog/en/pine-functions-support-dynamic-length-arguments-20554/
What am I doing wrong here? Thanks in advance.
I tried a variation of a solution posted by first user below with code
//#version=5
indicator("Dynamic INT array length", overlay = false, max_bars_back = 5000)
[a, b, hist] = ta.macd(close, 26, 12, 9)
int[] lengths = array.new_int()
int[] nlengths = array.new_int()
for i = 0 to 10
if hist[i] > 0
array.unshift(lengths, i)
else
array.unshift(nlengths,i)
lowest = ta.lowest(hist, array.get(lengths,0))
plot(lowest)
plot(hist, color = color.red)
debug = label.new(x = bar_index, y = 0, style = label.style_label_left, text = str.tostring(lowest) + " " + str.tostring(lengths) + " " + str.tostring(array.get(lengths,0)))
label.delete(debug[1])
and Im getting an error when using 'ta.lowest(hist, array.min(lengths))' where it says
Invalid value of the 'length' argument (0.0) in the "lowest" function. It must be > 0.
I tried all variations of the condition hist[i] > 0 within the for loop but nothing is printing and it has the same error. Let me know if there is an easy fix for this. Thanks.

It should be working, at a guess, normally I'd say there must be something going on with how the array is populated, but it doesn't seem to be the case here given the array output. It's unlikely, but possible you've found a bug, or an even possibly an exception that isn't being picked up by the compiler.
//#version=5
indicator("Dynamic INT array length", overlay = false, max_bars_back = 5000)
int[] lengths = array.new_int()
for i = 0 to 10
array.unshift(lengths, int(math.random(30, 50)))
[a, b, hist] = ta.macd(close, 26, 12, 9)
lowest = ta.lowest(hist, array.min(lengths))
plot(lowest)
plot(hist, color = color.red)
debug = label.new(x = bar_index, y = 0, style = label.style_label_left, text = str.tostring(lowest) + " " + str.tostring(lengths) + " " + str.tostring(array.min(lengths)))
label.delete(debug[1])
Follow up answer :
There's actually two things you need to take care of. If you consider when hist has been < 0 for a while (ie at least 10 bars). The first time hist crosses the zero line, your lengths array will only have one value : zero, and it can't be used in ta.lowest(). The second issue you will have is, if hist has been under zero the entire 10 bar window, the lengths array will be empty and array.get(lengths, 0) will give you the out of bounds indexing error.
You'll have to decide how to handle these specific circumstances, but the following of how you could account for it. For example using a length of 5 when the array has only one value of 0 and populating the arrays with na values to avoid the empty array problem.
//#version=5
indicator("Dynamic INT array length", overlay = false, max_bars_back = 5000)
[a, b, hist] = ta.macd(close, 26, 12, 9)
int[] lengths = array.new_int()
int[] nlengths = array.new_int()
for i = 0 to 10
if hist[i] > 0
array.unshift(lengths, i)
array.unshift(nlengths, na)
else
array.unshift(nlengths,i)
array.unshift(lengths, na)
int len = na
if array.get(lengths, 0) > 0
len := array.get(lengths, 0)
else
len := 5
lowest = ta.lowest(hist, len)
plot(lowest)
plot(hist, color = color.red)
debug = label.new(x = bar_index, y = 0, style = label.style_label_left, text = str.tostring(lowest) + " " + str.tostring(lengths) + " " + str.tostring(array.get(lengths,0)))
label.delete(debug[1])

Related

display 2 options side by side from array in gamemaker?

Recently I purchased gamemaker and followed Shaun Spalding's menu tutorial to get set up, but I've come across something that I want to change with the code. In the tutorial the options from the array are positioned so that they are one above the other, however for my game I want them to be right next to each other so that option 1 can be positioned on the left side of the screen, and option 2 on the right side of the screen on the same 'line' (but still able to switch between selecting either).
This is what it looks like currently.
As you can see, they are above each other, when really I want them side by side.
This is the code I have:
'Create' Event:
instruction[0] = "Back";
instruction[1] = "Start Game";
space = 100;
ipos = 0;
'Step' Event:
var move = 0;
move -= max(keyboard_check_pressed(vk_left),keyboard_check_pressed(ord("A")),0);
move += max(keyboard_check_pressed(vk_right),keyboard_check_pressed(ord("D")),0);
if (move != 0)
{
ipos += move;
if (ipos < 0) ipos = array_length_1d(instruction) - 1;
if (ipos > array_length_1d(instruction) - 1) ipos = 0;
}
var push;
push = max(keyboard_check_released(vk_enter),keyboard_check_released(vk_shift),keyboard_check_released(vk_space),0);
if (push == 1) scr_instructions();
'Draw' Event:
draw_set_halign(fa_left);
draw_set_valign(fa_middle);
draw_set_font(fnt_options);
draw_set_color(c_white);
var m;
for (m = 0; m < array_length_1d(instruction); m += 1)
{
draw_text(x + space, y + (m * space),string(instruction[m]))
}
draw_sprite(sprite_index, -1, x + 16, y + ipos * space - 21);
Anyone know what I need to change to get this to work?
Your draw_text seems to increase the y coordinate for each iteration in the loop.
Try to increase x using m instead.
Example:
draw_text(x + (m * space), y + space,string(instruction[m]))
You will likely have to adapt the spacing to get desired look.
Easiest is probably to hard code the coordinates instead of using a loop.
Do the same with draw_sprite.
draw_sprite(sprite_index, -1, x + 16 + ipos * space, y - 21);

node red global array variable - Get / Set not seeming to work

Working in Node-Red. I can use regular global variables across nodes and flows no problem. However, would like to use a global array variable.
Method A - desired functionality
I read in 16 data points at a time (type = double) and want to have them be index 0-15, then the following node would update indexes 16-31; then 32-45 and 46-64 in the last two nodes.
Node Red however, won't let update the array from the second node starting from index #16. I get "TypeError: Cannot read property 'indexOf' of undefined" error.
In lieu of Method A, I could have four different 16-index global arrays. However, accessing them gives erratic results. Trying to access index[n] returns the value from some other index - i.e. global.get("variable"[0]) returns variable[10] and global.get("variable"[1]) returns the value from variable[27].
This describes the problem -
https://www.youtube.com/watch?v=cF1bz8bEozI
Here is my sample flow:
[{"id":"ee1694d.7df4768","type":"i2c in","z":"d556390c.391838","name":"Read Camera","address":"105","command":"128","count":"32","x":240,"y":1480,"wires":[["9e27949c.512c28"]]},{"id":"d9eaa7a4.7f0ed8","type":"inject","z":"d556390c.391838","name":"ON","topic":"1","payload":"1","payloadType":"str","repeat":"","crontab":"","once":false,"x":70,"y":1480,"wires":[["ee1694d.7df4768"]]},{"id":"6dc0727a.4cf53c","type":"i2c in","z":"d556390c.391838","name":"Read Camera","address":"105","command":"160","count":"32","x":240,"y":1520,"wires":[["a7ac4b94.44ce58"]]},{"id":"d6d80973.784148","type":"i2c in","z":"d556390c.391838","name":"Read Camera","address":"105","command":"192","count":"32","x":240,"y":1560,"wires":[["b90d910d.8e743","ebeeb439.54cf18"]]},{"id":"b90d910d.8e743","type":"i2c in","z":"d556390c.391838","name":"Read Camera","address":"105","command":"224","count":"32","x":240,"y":1600,"wires":[["2f7b8dde.7a9902"]]},{"id":"6b1509e2.8bd4d8","type":"debug","z":"d556390c.391838","name":"Row 3,4","active":true,"console":"false","complete":"payload","x":1020,"y":1520,"wires":[]},{"id":"a828b6d2.40da08","type":"delay","z":"d556390c.391838","name":"","pauseType":"delay","timeout":"50","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":98,"y":1656,"wires":[["d6d80973.784148"]]},{"id":"ad0a1424.eaae08","type":"function","z":"d556390c.391838","name":"Save Global variables for Temperature","func":"global.set(\"RangeTemperaturesA\", 0);\n\nfor(i=0; i<16; i++){\n global.set(\"RangeTemperaturesA\"[i], msg.payload[i]); \n}\n\nreturn msg;","outputs":1,"noerr":0,"x":750,"y":1480,"wires":[["6b810d97.0beee4","6dc0727a.4cf53c"]]},{"id":"d386a34f.525d2","type":"function","z":"d556390c.391838","name":"Save Global variables for Temperature","func":"for(i=0; i<16; i++){\n global.set(\"RangeTemperatureB\"[i], msg.payload[i]); \n}\n\nreturn msg;","outputs":1,"noerr":0,"x":750,"y":1520,"wires":[["6b1509e2.8bd4d8"]]},{"id":"11c935c.be330ca","type":"function","z":"d556390c.391838","name":"Save Global variables for Temperature","func":"for(i=0; i<16; i++){\n global.set(\"RangeTemperatureC\"[i], msg.payload[i]); \n}\n\nreturn msg;","outputs":1,"noerr":0,"x":750,"y":1560,"wires":[[]]},{"id":"294185a.d5fe67a","type":"function","z":"d556390c.391838","name":"Save Global variables for Temperature","func":"for(i=0; i<16; i++){\n global.set(\"RangeTemperatureD\"[i], msg.payload[i]); \n}\n\nreturn msg;","outputs":1,"noerr":0,"x":750,"y":1600,"wires":[[]]},{"id":"3ffa9e84.cba002","type":"function","z":"d556390c.391838","name":"Find Max Temperature","func":"//n = Math.max(... global.get(\"RangeTemperature\"));\n\nreturn {payload: global.get(\"RangeTemperature\")};","outputs":1,"noerr":0,"x":900,"y":1660,"wires":[[]]},{"id":"9e27949c.512c28","type":"function","z":"d556390c.391838","name":"Get Temps full row","func":"var gridEye = [];\nvar loop=0;\n\nfor(n=0; n<32; n+=2){\n gridEye[loop] = ((msg.payload[n+1]<<8) | msg.payload[n]) * 0.25;\n //convert to F\n gridEye[loop] = ((5.0/3.0) * gridEye[loop] + 32.0).toFixed(2);\n //add right bitshit to reduce noise\n loop++;\n}\nmsg.payload=gridEye;\n\nreturn msg;","outputs":1,"noerr":0,"x":490,"y":1480,"wires":[["ad0a1424.eaae08"]]},{"id":"a7ac4b94.44ce58","type":"function","z":"d556390c.391838","name":"Get Temps full row","func":"var gridEye = []; //16-byte array with temperature readings\nvar loop=0;\n\nfor(n=0; n<32; n+=2){\n // Get raw values - bitshift left 8 bits then bitwise OR.\n // then take new value and multiply by 0.25 since it reads in 1/4 degree C\n gridEye[loop] = ((msg.payload[n+1]<<8) | msg.payload[n]) * 0.25;\n //convert to F\n gridEye[loop] = ((5.0/3.0) * gridEye[loop] + 32.0).toFixed(2);\n loop++;\n}\n\nmsg.payload=gridEye;\n\nreturn msg;","outputs":1,"noerr":0,"x":490,"y":1520,"wires":[["d386a34f.525d2"]]},{"id":"ebeeb439.54cf18","type":"function","z":"d556390c.391838","name":"Get Temps full row","func":"var gridEye = [];\nvar loop=0;\n/*\nvar pixel = 4;\nvar tmp = ((msg.payload[pixel*2 + 1]<<8) | msg.payload[pixel*2])*0.25; \n//gridEye reads in .25 degree C\ntmp = ((5/3 * tmp) + 32.0); //convert to F\n*/\n\nfor(n=0; n<32; n+=2){\n gridEye[loop] = ((msg.payload[n+1]<<8) | msg.payload[n]) * 0.25;\n //convert to F\n gridEye[loop] = ((5.0/3.0) * gridEye[loop] + 32.0).toFixed(2);\n //add right bitshit to reduce noise\n loop++;\n}\n/*\nfor(n=0; n<8; n++){\n gridEye[n]= ((n/35536 * 60 ) + 20);\n //convert to F\n //gridEye[n] = (((5.0/3.0) * gridEye[n]) + 32).toFixed(2);\n}\n*/\nmsg.payload=gridEye;\n\nreturn msg;","outputs":1,"noerr":0,"x":490,"y":1560,"wires":[["11c935c.be330ca"]]},{"id":"2f7b8dde.7a9902","type":"function","z":"d556390c.391838","name":"Get Temps full row","func":"var gridEye = [];\nvar loop=0;\n/*\nvar pixel = 4;\nvar tmp = ((msg.payload[pixel*2 + 1]<<8) | msg.payload[pixel*2])*0.25; \n//gridEye reads in .25 degree C\ntmp = ((5/3 * tmp) + 32.0); //convert to F\n*/\n\nfor(n=0; n<32; n+=2){\n gridEye[loop] = ((msg.payload[n+1]<<8) | msg.payload[n]) * 0.25;\n //convert to F\n gridEye[loop] = ((5.0/3.0) * gridEye[loop] + 32.0).toFixed(2);\n //add right bitshit to reduce noise\n loop++;\n}\n/*\nfor(n=0; n<8; n++){\n gridEye[n]= ((n/35536 * 60 ) + 20);\n //convert to F\n //gridEye[n] = (((5.0/3.0) * gridEye[n]) + 32).toFixed(2);\n}\n*/\nmsg.payload=gridEye;\n\nreturn msg;","outputs":1,"noerr":0,"x":490,"y":1600,"wires":[["294185a.d5fe67a"]]},{"id":"a0de3101.0c307","type":"function","z":"d556390c.391838","name":"Read from A","func":"var p = global.get(\"RangeTemperaturesA\"[1]);\nmsg.payload = p;\nreturn msg;","outputs":1,"noerr":0,"x":510,"y":1780,"wires":[["dbb0935d.742f7"]]},{"id":"dbb0935d.742f7","type":"debug","z":"d556390c.391838","name":"test A","active":true,"console":"false","complete":"payload","x":670,"y":1860,"wires":[]},{"id":"f6c50374.59f","type":"function","z":"d556390c.391838","name":"Read from B","func":"var n = global.get(\"RangeTemperatureB\"[0]);\nreturn {payload: n};","outputs":1,"noerr":0,"x":770,"y":1780,"wires":[["3e8947bc.be49b8"]]},{"id":"6b810d97.0beee4","type":"debug","z":"d556390c.391838","name":"Row 1,2","active":true,"console":"false","complete":"payload","x":1020,"y":1480,"wires":[]},{"id":"3e8947bc.be49b8","type":"debug","z":"d556390c.391838","name":"test b","active":true,"console":"false","complete":"payload","x":910,"y":1860,"wires":[]},{"id":"23da3f7f.1c4f8","type":"inject","z":"d556390c.391838","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":340,"y":1780,"wires":[["a0de3101.0c307"]]},{"id":"2a146fa7.577fc","type":"inject","z":"d556390c.391838","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":580,"y":1720,"wires":[["f6c50374.59f"]]}]
Edit -
I did a quick test -
For global.set -
global.set("RangeTemperaturesA", i)[i]; gives "TypeError: Cannot read property '0' of undefined"
global.set("RangeTemperaturesA[i]", i); gives "Error: Invalid property expression: unexpected i at position 19"
global.set("RangeTemperaturesA"[i], i); appears to probably work.
Sample code:
for(i=0; i<16; i++){
global.set("RangeTemperaturesA"[i], i);
node.warn("Value: " + i);
}
return msg;
Global.get -
global.get("RangeTemperaturesA"[n]) gives erratic results.
global.get("RangeTemperaturesA[n]") gives "Error: Invalid property expression: unexpected n at position 19"
global.get("RangeTemperaturesA")[n] gives "Value: undefined; Count: 0" gives "Value: undefined; Count: 0" which is perhaps the most promising if the array was never populated correctly.
Sample code:
for(n=0; n<16; n++){
node.warn("Value: " + global.get("RangeTemperaturesA")[n] + "; Count: " + n);
}
return msg;
The problem is due to the way you're trying to address the individual array entries.
With the code: global.get("variable"[0]), you are asking it to use the 0th element of the string "variable" as the argument passed to the get function. In otherwords, it is equivalent to: global.get("v")
Similarly, global.get("variable"[2]) will be equivalent to global.get("r").
You should either move array index inside the quotes:
global.get("variable[0]");
or access the 0th element of the result of the get function:
global.get("variable")[0];
The same holds true for how you are trying to use the set function.
Updates to reflect edits to the quesiton
None of your attempts to use global.set() are correct:
global.set("RangeTemperaturesA", i)[i] - here you are setting the global property RangeTemperaturesA to the value of i. The function set doesn't return anything, so attempting to treat it as an array is just wrong.
global.set("RangeTemperaturesA[i]", i); - this is the closest of the three, however, you are setting the string literal RangeTemperaturesA[i] - JavaScript doesn't know you want the i in the middle of that string to be the value of your local variable i.
global.set("RangeTemperaturesA"[i], i); - no. This is the same error as you had in the original question. "RangeTemperaturesA"[i] will evalute to the ith character of the string RangeTemperaturesA.
To do it properly, you want to use "RangeTemperaturesA["+i+"]" as the key:
global.set("RangeTemperaturesA["+i+"]", i);
When i is 0, that will generate the key RangeTemperaturesA[0].
The same applies for global.get:
var myValue = global.get("RangeTemperaturesA["+i+"]");
All of these examples assume you have already set RangeTemperaturesA to be an array:
global.set("RangeTemperaturesA",[]);

MATLAB preallocating space to a while loop

I have been unable to find sufficient examples that will help me with my problem of preallocating space to my loop.
I have the following code for my while loop:
Time = [];
Pressure = [];
ii = 1;
while ii<=20000
Pressure_Data = fread(fileID, 2);
Pressure = [Pressure;Pressure_Data];
Time_Data = fread(fileID, 8);
Time = [Time;Time_Data];
ii = ii + 1;
end
I then get the warning squiggle under Pressure_Data and Time-Data "Appears to change size on every loop iteration. Consider preallocating for speed."
So I would like to preallocate space because at the moment the time to read the file and store the data takes some time.
My attempt thus far:
Time = zeros(160000,1);
Pressure = zeros(40000,1);
However I just get an array of zeros and not the read and stored values I require
The current Pressure- and Time-values are appended to the existing arrays:
Pressure = [Pressure;Pressure_Data];
Time = [Time;Time_Data];
What you actually want is to write the current value to the correct position in the array. This is done by
Pressure(2*ii-1 : 2*ii) = Pressure_Data;
Time(8*ii-7 : 8*ii) = Time_Data;
The indexes are made up as follows: In the first iteration (ii=1), we write to Pressure(1 : 2) and Time(1 : 8). In the second iteration (ii=2), we write to Pressure(3 : 4) and Time(9 : 16), and so on.
Another small input: as you let ii go from 1 to 20000, you can also use a for loop:
for ii=1:20000
Pressure(2*ii-1 : 2*ii) = fread(fileID, 2);
Time(8*ii-7 : 8*ii) = fread(fileID, 8);
end

Returning a data-frame from C to R -

I followed this link
Passing a data frame from-to R and C using .call()
to find the way to access an R data frame inside C.
My requirement is the opposite of that. I have a tabular data in C and need to create an R data frame object in C and return it on as SEXP.
For simple R vectors and lists creation, I followed something like in this link
http://adv-r.had.co.nz/C-interface.html
But I am still wondering how to create a dataframe and return from C to R. Considering a dataframe is a list, I tried creating a list and passing it on, but it expectedly gets me a list in R and not a dataframe.
Any help would be appreciated.
You may make use of the fact that a data.frame object is a list consisting of atomic vectors, each having the same length, with names, class, and row.names attributes properly set:
library(inline)
f <- cxxfunction(signature(), body='
SEXP ret, ans1, ans2, cls, nam, rownam;
PROTECT(ret = Rf_allocVector(VECSXP, 2)); // a list with two elements
PROTECT(ans1 = Rf_allocVector(INTSXP, 3)); // first column
PROTECT(ans2 = Rf_allocVector(INTSXP, 3)); // second column
for (int i=0; i<3; ++i) { // some data
INTEGER(ans1)[i] = i+1;
INTEGER(ans2)[i] = -(i+1);
}
SET_VECTOR_ELT(ret, 0, ans1);
SET_VECTOR_ELT(ret, 1, ans2);
PROTECT(cls = allocVector(STRSXP, 1)); // class attribute
SET_STRING_ELT(cls, 0, mkChar("data.frame"));
classgets(ret, cls);
PROTECT(nam = allocVector(STRSXP, 2)); // names attribute (column names)
SET_STRING_ELT(nam, 0, mkChar("a"));
SET_STRING_ELT(nam, 1, mkChar("b"));
namesgets(ret, nam);
PROTECT(rownam = allocVector(STRSXP, 3)); // row.names attribute
SET_STRING_ELT(rownam, 0, mkChar("1"));
SET_STRING_ELT(rownam, 1, mkChar("2"));
SET_STRING_ELT(rownam, 2, mkChar("3"));
setAttrib(ret, R_RowNamesSymbol, rownam);
UNPROTECT(6);
return ret;
')
Which yields:
print(f())
## a b
## 1 1 -1
## 2 2 -2
## 3 3 -3
Obligatory Rcpp example:
// [[Rcpp::export]]
DataFrame createTwo(){
IntegerVector v = IntegerVector::create(1,2,3);
std::vector<std::string> s(3);
s[0] = "a";
s[1] = "b";
s[2] = "c";
return DataFrame::create(Named("a")=v, Named("b")=s);
}
which will get you a 3x2 data.frame with one char vector and one int vector.

Qsorting a multidimensional array

I am currently working on an algorithm, that requires my multidimensional array (currently 3-dimensional) to be sorted by value of sum of first and second item. Specifically:
(condition for item i and j to be swapped)
if ((Array[i][1]+Array[i][2]) > (Array[j][1]+Array[j][2])) return 1;
I have decided, for test purposes, to use select sort. However, my algorithm is required to do all its magic in under 5 seconds. Select sort needs for itself around 10 seconds to sort such array, if it has around 200 000 items.
I have decided to use a better algorithm, since I'm pretty confident in rest of my program. I am aware that unix systems contain a built-in quicksort function, qsort (available through man qsort in terminal). However, I do not know how to implement it.
My idea was to create another array, one dimensional (1D), with same length, containing indexes of items in main array. Through that, I might be able to sort only the secondary 1D array, where first item will have index of item in main array with smallest sum, second will have the second smallest, and so on.
However, how can I do it? Qsort function needs to be provided with comparing function, to decide whether to swap, or not. If I did make my own comparing function (like the one I stated in begin of my question), how can I address with something like (Array[SeconArray[i]][0]), when main Array is only specified in main of the function, and therefore cannot be accessed through another function in same file?
I'll be glad for any tips or tricks how to solve this. I'm also not keen on using qsort. If you think that another sorting algorithm can do better, please, let me know.
Thanks a lot
I've only a limited amount of time to post this, but hopefully the idea is clear. This is one way qsort can be setup to do what you're looking for. This is a 2D array Nx3 that I've populated with random values from [0.0,500). The idea can be extended to a 3D and beyond array.
The trick is to get the row width correct (or in the case of 3D the slab, 4D the cube, etc...)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int cmp_row(const void* arg1, const void* arg2)
{
const double *ar1 = arg1;
const double *ar2 = arg2;
double diff = (ar1[1] + ar1[2] - ar2[1] - ar2[2]);
return (diff < 0.0) ? -1 : (0.0 < diff);
}
int main(int argc, char *argv[])
{
static const int N = 50;
double (*ar)[3] = NULL;
int i=0;
// see prng
srand((unsigned)time(NULL));
// allocat space for Nx3 2D array.
ar = calloc(N, sizeof(*ar));
// since I've no test data, random fill with values
// from [0..500)
for (i=0;i<N;++i)
{
ar[i][1] = ((double)rand()/(double)RAND_MAX)*500.0;
ar[i][2] = ((double)rand()/(double)RAND_MAX)*500.0;
}
// sort by elements 1+2
qsort(ar, N, sizeof(*ar), cmp_row);
for (i=0;i<N;++i)
{
printf("%3d : %7.3f + %7.3f = %7.3f\n",
i+1, ar[i][1], ar[i][2], ar[i][1]+ar[i][2]);
}
// release allocation
free(ar);
return 0;
}
Note: This gets a little more complex when dealing with what I called the syntax-only 2D+ arrays. Those would me the "arrays" that are actually vectors of pointers. int **ar etc. The premise is nearly the same, however, and only the comparator would have to change. If I've the time I'll add such a beast as an additional sample if input warrants it.
Final Note: This does not protect from potential overflow or underflow of the floating point values. a considerably more complex boolean-logic-only comparator can do that, but unless your data is uber-sensitive to such extremes, its hardly worth it for this example.
Output (obviously your's will vary)
I've included the summation of ar[i][1] + ar[i][2] as evidence of the sorting order doing what I believe you want. I hope this helps.
1 : 47.986 + 1.471 = 49.457
2 : 114.418 + 26.848 = 141.267
3 : 148.183 + 12.145 = 160.328
4 : 46.925 + 161.231 = 208.155
5 : 102.405 + 116.097 = 218.502
6 : 58.676 + 172.490 = 231.167
7 : 144.797 + 99.977 = 244.774
8 : 8.914 + 314.920 = 323.833
9 : 68.885 + 255.924 = 324.809
10 : 107.825 + 220.631 = 328.457
11 : 287.056 + 44.610 = 331.665
12 : 217.505 + 114.799 = 332.304
13 : 240.620 + 104.506 = 345.127
14 : 242.288 + 133.509 = 375.797
15 : 381.538 + 4.073 = 385.611
16 : 4.991 + 383.519 = 388.510
17 : 257.611 + 163.872 = 421.483
18 : 43.278 + 380.951 = 424.230
19 : 300.775 + 129.879 = 430.654
20 : 134.814 + 314.688 = 449.502
21 : 103.281 + 346.874 = 450.155
22 : 197.761 + 263.668 = 461.429
23 : 303.872 + 173.430 = 477.302
24 : 466.265 + 11.400 = 477.665
25 : 108.817 + 391.995 = 500.812
26 : 467.992 + 40.985 = 508.977
27 : 353.493 + 160.398 = 513.891
28 : 406.446 + 130.214 = 536.659
29 : 244.678 + 303.989 = 548.667
30 : 303.282 + 260.434 = 563.716
31 : 254.139 + 317.150 = 571.290
32 : 368.311 + 203.118 = 571.429
33 : 372.654 + 201.597 = 574.251
34 : 143.985 + 454.796 = 598.781
35 : 254.561 + 402.038 = 656.598
36 : 309.922 + 363.872 = 673.795
37 : 196.554 + 478.447 = 675.000
38 : 493.585 + 185.749 = 679.334
39 : 438.196 + 257.858 = 696.054
40 : 347.198 + 360.908 = 708.107
41 : 262.210 + 456.034 = 718.244
42 : 389.174 + 339.315 = 728.489
43 : 300.199 + 446.422 = 746.621
44 : 344.346 + 427.167 = 771.513
45 : 317.604 + 470.313 = 787.917
46 : 312.785 + 475.855 = 788.640
47 : 334.682 + 492.928 = 827.609
48 : 399.056 + 430.449 = 829.505
49 : 460.128 + 373.025 = 833.154
50 : 419.137 + 440.745 = 859.882

Resources