AS3: Minimum value from that is not 0? - actionscript-3

I have a problem:
Is there any way I can find the minimum value of an Array that is not 0? Let's say I have this Array:
{0,2,0,0,1} and I want it to find 1.

It should just be a slight variation on finding the minimum including zero. This would be achieved by setting the minimum to the first value and then going through all the others, replacing the minimum if a value in the array is lower.
The modification needed to that for your scenario is to just ignore those having a value of zero. Something like this should do:
var numbers:Array = [0,2,0,0,1];
var started:Boolean = false;
var minval:Number = 0;
for each (var num:Number in numbers) {
if ((!started) && (num != 0)) {
started = true;
minval = num;
}
if ((started) && (num != 0) && (num < minval)) {
minval = num;
}
}
The first if statement will be the only one executed until you find the first non-zero value, at which point you'll set started and store that number as the minimum.
From then on (including on that iteration), you'll just check the non-zero numbers to see if they're less and store them if so.
At the end, either started will be false in which case there were no non-zero numbers, or started will be true and minval will hold the smallest number found.

Related

Interpolate function in Google Scripts

I am using google sheets to log my water usage and want to find out how much I have used in a given period by using linear interpolation. I would really like to use a function similar to forecast, but instead of using the entire range to interpolate, just use the nearest points above and below.
I am keen to try and code it myself (have done lots of VBA) but don't know really where to start with google scripts. Does anyone have a starting point for me?
The process I would take is:
Interpolate(x, data_y, data_x)
// Check value is within range of known values (could expand function to use closet two values and extrapolate...)
(is X within XMin and XMax)
// Find closet X value below (X1), corresponding Y1
// Find closet X value above (X2), corresponding Y2
Return Y = Y1+(X-X1)*((Y2-Y1)/(X2-X1))
function interpolation(x_range, y_range, x_value) {
var xValue, yValue, xDiff, yDiff, xInt, index, check = 0;
if(x_value > Math.max.apply(Math, x_range) || x_value < Math.min.apply(Math, x_range)) {
throw "value can't be interpolated !!";
return;
}
for(var i = 0, iLen = x_range.length; i < iLen-1; i++) {
if((x_range[i][0] <= x_value && x_range[i+1][0]> x_value) || (x_range[i][0] >= x_value && x_range[i+1][0] < x_value)){
yValue = y_range[i][0];
xDiff = x_range[i+1][0] - x_range[i][0];
yDiff = y_range[i+1][0] - yValue;
xInt = x_value - x_range[i][0];
return (xInt * (yDiff / xDiff)) + yValue;
}
}
return y_range[x_range.length-1][0];
}

AS3: adding different numbers in an array to get specific result.

I got a numberArray.
It contains intergers - randomised, within a specific range.
I want to get a specific sum, but not for everything inside the numberArray,
more of trying to sum up different amount of numbers (total of 5 only) inside the numberArray and see if it'll get the specific total required. and if not, it'll randomise another number to take over one of the numbers inside the numberArray.
What's the easiest way to do this ?
doing lots of
if (numberArray[1] + numberArray[2] == specificNumber)
{
}
if (numberArray[1] + numberArray[3] == specificNumber)
{
}
etc. etc. etc.
have too many lines of codes, and it seems like there are easier codes. right now i only have 5 different numbers in the array, so it's still bearable, but if the amount of numbers are higher.... ....
Reading your question like this: For your array of random integers, find a (or all) set(s) of integers that have a given sum.
This is an NP-Complete problem - i.e. there's no known algorithm that solves it efficiently.
The fastest known way is rather complex, so we'll go with a naive solution - should be good enough if you're not doing this on every frame or the input set is huge.
This should also work with 0 or negative values in the input set.
// The sum we're looking for:
var requiredSum:int = 8;
// Our input set:
var numberArray:Array = [1, 2, 3, 4, 5, 2, 3];
// Results will be stored here:
var resultSets:Array = [];
// Go through all possible subset sizes.
// This allows subset sizes all the way up to the size of
// the input set (numberArray.length).
// You can modify it to a fixed value (say, 5), of course:
for (var subsetSize:int = 1; subsetSize <= numberArray.length; subsetSize++)
{
// We'll use the same array for all our attempts of this size:
var subset:Array = new Array(subsetSize);
findSum(numberArray, subset, 0, 0);
}
// Output results:
for (var i:int = 0; i < resultSets.length; i++)
{
trace(resultSets[i].join("+"));
}
// numberArray : Our input set
// subset : The set we're currently filling
// setIndex : The position we're at in numberArray
// subsetIndex : The position we're at in the set we're filling
function findSum(numberArray:Array, subset:Array, setIndex:int,
subsetIndex:int):void
{
// Try every value from the input set starting from our current position,
// and insert the value at the current subset index:
for (var index:int = setIndex ; index < numberArray.length; index++)
{
subset[subsetIndex] = numberArray[index];
// Have we filled the subset?
if (subsetIndex == subset.length - 1)
{
var sum:int = 0;
for (var i:int = 0; i < subset.length; i++)
{
sum += subset[i];
}
if (sum == requiredSum)
{
// Clone the array before adding it to our results,
// since we'll be modifying it if we find more:
resultSets.push(subset.concat());
}
}
else
{
// Recursion takes care of combining our subset so far
// with every possible value for the remaining subset indices:
findSum(numberArray, subset, index + 1, subsetIndex + 1);
}
}
}
Output for the values used in the above code:
3+5
5+3
1+2+5
1+3+4
1+4+3
1+5+2
2+3+3
2+4+2
3+2+3
1+2+3+2
1+2+2+3
If we only need to know IF a sum exists, there's no need for the result set - we just return true/false, and break out of the recursive algorithm completely when a sum has been found:
var requiredSum:int = 8;
var numberArray:Array = [1, 2, 3, 4, 5, 2, 3];
// Go through all possible subset sizes:
for (var subsetSize:int = 1; subsetSize <= numberArray.length; subsetSize++)
{
// We'll use the same array for all our attempts of this size:
var subset:Array = new Array(subsetSize);
if (findSum(numberArray, subset, 0, 0))
{
trace("Found our sum!");
// If we found our sum, no need to look for more sets:
break;
}
}
// numberArray : Our input set
// subset : The set we're currently filling
// setIndex : The position we're at in numberArray
// subsetIndex : The position we're at in the set we're filling
// RETURNS : True if the required sum was found, otherwise false.
function findSum(numberArray:Array, subset:Array, setIndex:int,
subsetIndex:int):Boolean
{
// Try every value from the input set starting from our current position,
// and insert the value at the current subset index:
for (var index:int = setIndex ; index < numberArray.length; index++)
{
subset[subsetIndex] = numberArray[index];
// Have we filled the subset?
if (subsetIndex == subset.length - 1)
{
var sum:int = 0;
for (var i:int = 0; i < subset.length; i++)
{
sum += subset[i];
}
// Return true if we found our sum, false if not:
return sum == requiredSum;
}
else
{
if (findSum(numberArray, subset, index + 1, subsetIndex + 1))
{
// If the "inner" findSum found a sum, we're done, so return
// - otherwise stay in the loop and keep looking:
return true;
}
}
}
// We found no subset with our required sum this time around:
return false;
}
ETA: How this works... As mentioned, it's the naive solution - in other words, we're simply checking every single permutation of numberArray, summing each permutation, and checking if it's the sum we want.
The most complicated part is making all the permutations. The way this code does it is through recursion - i.e., the findSum() function filling a slot then calling itself to fill the next one, until all slots are filled and it can check the sum. We'll use the numberArray [1, 5, 4, 2] as an example here:
Go through all subset sizes in a loop - i.e., start by making all [a], then all [a,b], [a,b,c], [a,b,c,d]... etc.
For each subset size:
Fill slot 1 of the subset...
... with each value of numberArray - [1, ?, ?], [5, ?, ?], [4, ?, ?]...
If all slots in subset have been filled, check if the sum matches and skip step 4.
(Recursively) call findSum to:
Fill slot 2 of the subset...
... with each remaining value of numberArray - [1, 5, ?], [1, 4, ?], [1, 2, ?]
If all slots in subset have been filled, check if the sum matches and skip step 4.
(Recursively) call findSum to:
Fill slot 3 of the subset
... with each remaining value of numberArray - [1, 5, 4], [1, 5, 2]
If all slots in subset have been filled, check if the sum matches and skip step 4.
(Recursively) call findSum (this goes on "forever", or until all slots are filled and we "skip step 4")
Go to 2.4.4.1. to try next value for slot 3.
Go to 2.4.1 to try next value for slot 2.
Go to 2.1 to try next value for slot 1.
This way, we go through every permutation of size 1, 2, 3, 4...
There's more optimization that could be done here, since the code never checks that it actually has enough values left in the input set to fill the remaining slots - i.e. it does some loops and calls to findSum() that are unneeded. This is only a matter of efficiency, however - the result is still correct.
I would do something like the following:
shuffle array
take random amount of numbers from the array
sum them up
if the sum is not the total sum you want, repeat
hm, not sure what you want to do at the end when a "conclusion" or "no conclusion" is reached, but you could generate a Power set from your set of numbers then for each subset add up all the numbers in it to see if you get your desired sum.
(This would be a 'brute force' approach and could be slow if you have many numbers.)
Possibly useful for how to create a Power set:
Calculating all of the subsets of a set of numbers

AS3 math: nearest neighbour in array

So let's say i have T, T = 1200. I also have A, A is an array that contains 1000s of entries and these are numerical entries that range from 1000-2000 but does not include an entry for 1200.
What's the fastest way of finding the nearest neighbour (closest value), let's say we ceil it, so it'll match 1201, not 1199 in A.
Note: this will be run on ENTER_FRAME.
Also note: A is static.
It is also very fast to use Vector.<int>instead of Arrayand do a simple for-loop:
var vector:Vector.<int> = new <int>[ 0,1,2, /*....*/ 2000];
function seekNextLower( searchNumber:int ) : int {
for (var i:int = vector.length-1; i >= 0; i--) {
if (vector[i] <= searchNumber) return vector[i];
}
}
function seekNextHigher( searchNumber:int ) : int {
for (var i:int = 0; i < vector.length; i++) {
if (vector[i] >= searchNumber) return vector[i];
}
}
Using any array methods will be more costly than iterating over Vector.<int> - it was optimized for exactly this kind of operation.
If you're looking to run this on every ENTER_FRAME event, you'll probably benefit from some extra optimization.
If you keep track of the entries when they are written to the array, you don't have to sort them.
For example, you'd have an array where T is the index, and it would have an object with an array with all the indexes of the A array that hold that value. you could also put the closest value's index as part of that object, so when you're retrieving this every frame, you only need to access that value, rather than search.
Of course this would only help if you read a lot more than you write, because recreating the object is quite expensive, so it really depends on use.
You might also want to look into linked lists, for certain operations they are quite a bit faster (slower on sort though)
You have to read each value, so the complexity will be linear. It's pretty much like finding the smallest int in an array.
var closestIndex:uint;
var closestDistance:uint = uint.MAX_VALUE;
var currentDistance:uint;
var arrayLength:uint = A.length;
for (var index:int = 0; index<arrayLength; index++)
{
currentDistance = Math.abs(T - A[index]);
if (currentDistance < closestDistance ||
(currentDistance == closestDistance && A[index] > T)) //between two values with the same distance, prefers the one larger than T
{
closestDistance = currentDistance;
closestIndex = index;
}
}
return T[closestIndex];
Since your array is sorted you could adapt a straightforward binary search (such as explained in this answer) to find the 'pivot' where the left-subdivision and the right-subdivision at a recursive step bracket the value you are 'searching' for.
Just a thought I had... Sort A (since its static you can just sort it once before you start), and then take a guess of what index to start guessing at (say A is length 100, you want 1200, 100*(200/1000) = 20) so guess starting at that guess, and then if A[guess] is higher than 1200, check the value at A[guess-1]. If it is still higher, keep going down until you find one that is higher and one that is lower. Once you find that determine what is closer. if your initial guess was too low, keep going up.
This won't be great and might not be the best performance wise, but it would be a lot better than checking every single value, and will work quite well if A is evenly spaced between 1000 and 2000.
Good luck!
public function nearestNumber(value:Number,list:Array):Number{
var currentNumber:Number = list[0];
for (var i:int = 0; i < list.length; i++) {
if (Math.abs(value - list[i]) < Math.abs(value - currentNumber)){
currentNumber = list[i];
}
}
return currentNumber;
}

C++ if statement seems to ignore the argument

Here's the code.
bool b_div(int n_dividend)
{
for (int iii = 10 ; iii>0 ; iii--)
{
int n_remainder = n_dividend%iii;
if (n_remainder != 0)
return false;
if (iii = 1)
return true;
}
}
After testing this function I made for a program, the function seems to stop at the if (n_remainder != 0) part. Now then the function SHOULD test if the number that the function takes in can be divided by all numbers from 10 to 1.(it takes in numbers until it returns true) I know the first number that this works with it is 2520 but even on this number it stops at if(n_remainder != 0). So I was hoping for some advice! Im having trouble troubleshooting it! Any links or words I should look for would be awesome! Im still pretty new to programming so any help you can give for learning would rock! Thanks!
Change your last if statement to:
if (iii == 1)
return true;
Currently you have only a single equals sign, which sets the variable iii to 1, and is always true. By using a double equals it will compare iii and 1.
In addition to SC Ghost's answer, you can actually also clean up your function a bit more :)
bool b_div(int n_dividend) {
for (int i = 10 ; i > 1 ; i--) {
int n_remainder = n_dividend % i;
if (n_remainder != 0) {
return false;
}
}
return true;
}
A few notes,
modulus of 1 will always be zero, so you only need to iterate while i > 1
you can completely remove the if(i == 1) check and just always return true after the for loop if the for loop doesn't return false. It basically removes an unnecessary check.
I think it's more standard to name your iterator iii as i, And I prefer brackets the way I wrote them above (this is of course completely personal preference, do as you please)

1D multiple peak detection?

I am currently trying to implement basic speech recognition in AS3. I need this to be completely client side, as such I can't access powerful server-side speech recognition tools. The idea I had was to detect syllables in a word, and use that to determine the word spoken. I am aware that this will grealty limit the capacities for recognition, but I only need to recognize a few key words and I can make sure they all have a different number of syllables.
I am currently able to generate a 1D array of voice level for a spoken word, and I can clearly see, if I somehow draw it, that there are distinct peaks for the syllables in most of the cases. However, I am completely stuck as to how I would find out those peaks. I only really need the count, but I suppose that comes with finding them. At first I thought of grabbing a few maximum values and comparing them with the average of values but I had forgot about that peak that is bigger than the others and as such, all my "peaks" were located on one actual peak.
I stumbled onto some Matlab code that looks almost too short to be true, but I can't very that as I am unable to convert it to any language I know. I tried AS3 and C#. So I am wondering if you guys could start me on the right path or had any pseudo-code for peak detection?
The matlab code is pretty straightforward. I'll try to translate it to something more pseudocodeish.
It should be easy to translate to ActionScript/C#, you should try this and post follow-up questions with your code if you get stuck, this way you'll have the best learning effect.
Param: delta (defines kind of a tolerance and depends on your data, try out different values)
min = Inf (or some very high value)
max = -Inf (or some very low value)
lookformax = 1
for every datapoint d [0..maxdata] in array arr do
this = arr[d]
if this > max
max = this
maxpos = d
endif
if this < min
min = this
minpos = d
endif
if lookformax == 1
if this < max-delta
there's a maximum at position maxpos
min = this
minpos = d
lookformax = 0
endif
else
if this > min+delta
there's a minimum at position minpos
max = this
maxpos = d
lookformax = 1
endif
endif
Finding peaks and valleys of a curve is all about looking at the slope of the line. At such a location the slope is 0. As i am guessing a voice curve is very irregular, it must first be smoothed, until only significant peaks exist.
So as i see it the curve should be taken as a set of points. Groups of points should be averaged to produce a simple smooth curve. Then the difference of each point should be compared, and points not very different from each other found and those areas identified as a peak, valleys or plateau.
If anyone wants the final code in AS3, here it is:
function detectPeaks(values:Array, tolerance:int):void
{
var min:int = int.MIN_VALUE;
var max:int = int.MAX_VALUE;
var lookformax:int = 1;
var maxpos:int = 0;
var minpos:int = 0;
for(var i:int = 0; i < values.length; i++)
{
var v:int = values[i];
if (v > max)
{
max = v;
maxpos = i;
}
if (v < min)
{
min = v;
minpos = i;
}
if (lookformax == 1)
{
if (v < max - tolerance)
{
canvas.graphics.beginFill(0x00FF00);
canvas.graphics.drawCircle(maxpos % stage.stageWidth, (1 - (values[maxpos] / 100)) * stage.stageHeight, 5);
canvas.graphics.endFill();
min = v;
minpos = i;
lookformax = 0;
}
}
else
{
if (v > min + tolerance)
{
canvas.graphics.beginFill(0xFF0000);
canvas.graphics.drawCircle(minpos % stage.stageWidth, (1 - (values[minpos] / 100)) * stage.stageHeight, 5);
canvas.graphics.endFill();
max = v;
maxpos = i;
lookformax = 1;
}
}
}
}