# Making number of elements in a list smaller, but keeping the same sum and "ratios" between elements

Hello everyone!

I’m trying to write a function that scales the size of a list (specifically in my case containing amplitudes, but I’m trying to write a general-purpose function), while keeping the ratios between the elements in the list “true” to the original list.

For example if I want list_a containing 10 values to become list_b containing 8 values, I know that the first element in the new list has to be list_a[0] + list_a[1]*0.25. 0.25 because it needs 25% of the element at index1 to keep the “ratios” from the first list.
I tried writing a code that simulates this logic of getting percentages from the indexes through the first list, but it’s giving me a real headache, and there has to be a simpler way to do this?
My code looks like this:

``````(
var list = [1,2,3,1,2,3,1,2,4,5];
var div = 8;
var incr = list.size/div;
var out = Array(div);
var current = 0;
div.do{
var from = current.value;
var to = current.value + incr;
var intDist = ~distance.value(from.asInt, to.asInt);
var realDist = ~distance.value(from, to);
var modulo1 = 1-from%1;
var modulo2 = to%1;
var temp_val = 0;

realDist.postln;
if(intDist == 0, {temp_val = temp_val + (list[from.asInt]*realDist)}, {
if(intDist == 1, {
if(modulo1 == 0.0, {
temp_val = temp_val + list[from.asInt];
temp_val = temp_val + ((modulo2)*list[to.asInt]);
}, {
temp_val = temp_val + ((modulo1)*list[from.asInt]);
temp_val = temp_val + ((modulo2)*list[to.asInt]);
});
if(modulo2 == 0.0, {
temp_val = temp_val + list[to.asInt];
temp_val = temp_val + ((modulo1)*list[from.asInt]);
});
});
if(intDist > 1, {
if(modulo1 == 0.0, {
temp_val = temp_val + list[from.asInt];
temp_val = temp_val + (list[from.asInt+1..to.asInt-1].sum);
temp_val = temp_val + ((modulo2)*list[to.asInt]);
}, {
temp_val = temp_val + ((modulo1)*list[from.asInt]);
temp_val = temp_val + (list[from.asInt+1..to.asInt-1].sum);
temp_val = temp_val + ((modulo2)*list[to.asInt]);
});
if(modulo2 == 0.0, {
temp_val = temp_val + ((modulo1)*list[from.asInt]);
temp_val = temp_val + (list[from.asInt+1..to.asInt-1].sum);
temp_val = temp_val + list[to.asInt];
});
});
});
current = current + incr;
temp_val;
};
out;
)
``````

I know my code is a total mess, but maybe someone understands what I’m trying to do and knows a simpler way of doing this?

Martin

how bout this?

``````{
| array newSize |
array.stutter(newSize).clump(array.size).collect(_.sum)/newSize
}
``````
1 Like

It sounds like you’re describing resampling with linear interpolation, which is already implemented by resamp1.

Downsampling will inevitably lose information though:

``````x = [1,2,3,1,2,3,1,2,4,5];

-> 2.25

x.blendAt(2.5);  // next step, halfway between
-> 2

x.blendAt(3.75);
-> 1.75
``````

… and your upward sawtooth pattern has become a lower-amplitude downward sawtooth.

In any case, resamp1 should do it all for you, and if not, blendAt will do the linear interpolation part.

hjh

1 Like

Exactely! I’m very impressed you understood what I meant

I tried resamp1, but it didn’t give me exactely what I was after. Maybe I have to use it in combination with blendAt?

I think I misunderstood what you meant by ratios being preserved. Perhaps `resamp1` isn’t the right answer… never mind

hjh