iterate through object using values instead of index - javascript

I have an array of mathematical operators stored as an object.
object {0: "-", 1: "*", 2: "/", 3: "+"} called numOperators
I don't know what order the operators will be in, but they need to be execued in the correct order of *, /, +, and - So when I reassign the above object into another parallel object, I assign the indexes of the above object with the order they need to be executed. Then i have this object:
Object {0: 2, 1: 0, 2: 1, 3: 3} called opArray
What I want to do is iterate through the object (which could be any length) by looking at the values instead of the indexes.
In summary, I want to iterate all of the values in the order 3, 2, 1, 0. Look for values of 3 until those are used up, then look for 2, then 1, then finally go through 0. I haven't been able to come up with an efficient way of doing this. Because mathematical operators need to be done in order, a temporary result value is created and then used for the next iteration. Eventually, they are all combined into a single result.
This is what I was trying last:
var valArray = {0: "3", 1: "8", 2: "4", 3: "8", 4: "2"};
var res=[];//temporary result values ordered by execution
var returnRes=0;
var op=0;
$.each(opArr, function(index, value) {//goes through the values in order
if(value==0){
op = numOperators[index]; //uses the indexes that matches the values
res[index]=operate(valArr[index], valArr[index+1],op);
returnRes=res[index];
console.log(res);
}
if(valuei>0){
op = numOperators[index];
res[index]=operate(res[index-1], valArr[index+1],op);
returnRes=res[index];
console.log(res);
}
});
return(returnRes);
I know I may be going about this the completely wrong way, so I'd appreciate some insight on what is an easier way to do this. Thanks!
To clarify further, I have a valid reason for taking this approach to math and not using eval(). Some of the numbers are derived from variables read in as text and converted. There could also be text (non-number text) that needs to be concatenated. So I need to get the math and text separated and evaluated differently. I figured an individual approach would be best.

The apparent solution seems to be using a for each loop. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for_each...in
The other thing you can do and what looks closer to your use case is to write an iterator for this. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators

You could make an array and sort it by value:
var opArray = {0: 2, 1: 0, 2: 1, 3: 3};
var array = [];
for (var key in opArray) {
array.push({
key: key,
value: opArray[key]
});
}
array.sort(function(a, b) {
return a.value < b.value;
});
console.log(JSON.stringify(array));
// will print
//[
// {"key":"3","value":3},
// {"key":"0","value":2},
// {"key":"2","value":1},
// {"key":"1","value":0}
//]
// So now you can iterate over the array in the correct order
// and access the key and value properties

Why not use an ordinary array:
var numOperators = ["-", "*", "/", "+"];
The access is via
numOperators.forEach(function (operator) {
// do something
});
possible.
Example
8*4, result/8, 3-result, result+2
var operators = ['*', '/', '-', '+'],
functions = {
'-': function (a, b) { return b - a; }, // spot the changed variables
'*': function (a, b) { return a * b; },
'/': function (a, b) { return a / b; },
'+': function (a, b) { return a + b; }
},
valArray = [8, 4, 8, 3, 2];
document.write(valArray.reduce(function (r, a, i) {
return functions[operators[i]](r, a);
}, valArray.shift()));

Related

Algorithm sorting array from closest to farthest by given number

I trying to came up algorithm in js for sorting from closest to farthest by given number, for example (number: 5.6666, array: [-1, 9, 4, 10, 11, 0]) should return [4, 9, 10, 0, 11, -1].Any idea how approach to the problem? A little gotcha actually my array is array of objects and I need sort by certain key in object. In docs said, that should use array.sort() with compare function, but I don't understand how implement this function.
The sort() function of Array can take a function:
[1,2,3].sort((a, b) => /* do something */)
Each time, you should return a value. A negative number will mean a comes before b. A positive number means b comes before a. 0 means they are equal.
If you want distance to the number, you want the absolute value, with Math.abs(). Assuming the key on the object is value, you can put it all together:
const target = 5;
const values = [{ value: -100 }, { value: 1 }, { value: 4 }, { value: 6 }, { value: 10 }];
const result = values.sort(({ value: a }, { value: b }) =>
Math.abs(target - a) - Math.abs(target - b));
console.log(result);
I used some ES6 destructuring to make it a bit cleaner by pulling the value out in the parameters.
If you wanted to just have the values remaining (instead of the objects), you can either use map() after the fact (or before).
Note, in the case of 2 numbers being equidistant from the target (in my example, 4 and 6 are both 1 away from the target), you can't guarantee which will come first. If it matters to you, you'll want to add some extra logic to hand that scenario.
Using sort, you can check each of their distances from your number.
var num = 5.666
var arr = [-1, 9, 4, 10, 11, 0]
arr.sort(function(a, b){
return Math.abs(num-a) - Math.abs(num-b);
});
console.log(arr)
Use array.sort and get the difference of each number from the input value given
var inputArray = [-1, 9, 4, 10, 11, 0],
input = 5;
var closest = inputArray.sort(function(a, b){
return Math.abs(input-a) - Math.abs(input-b);
});
console.log(closest);

Iterating through a function call

After years of writing loops in C++ the tedious way
for(int i=0; i<N; ++i) {
...
}
it becomes quite nice to use iterators
for(it i=v.begin(); i<v.end(); ++i) {
...
}
and ultimately moving to range iterators
for(auto i:v) {
...
}
In JavaScript also the for can be used, in a style nearly identical
(minus the type declaration and the pre/post increment operator) to
the first one above.
Still, in all of these the for is there. The D3.js
library demonstrates an alternative. One can iterate over an array by writing
d3.select("body")
.selectAll("p")
.data([4, 8, 15, 16, 23, 42])
.enter().append("p")
.text(function(d) { return "I’m number " + d + "!"; });
Here the enter mutates to a for loop. The documentation
explains nicely the client-side view of joins. What I am missing is a
standalone example of the (functional programming?) style of
converting a function call to an iteration.
No doubt this is not unique to D3.js. This is just where I encountered the idiom.
Can you suggest a few lines of standalone JavaScript code that
demonstrate iteration through a function call?
There are at least a couple of built-in functions that come to my mind.
map()
This one is very obvious.
[1, 2, 3]
.map(someNumber => someNumber * someNumber)
.map((powered, index) => index + "::" + powered);
// --> [ "1::1", "2::4", "3::9" ]
Chains well, right? Takes some input and produces the result consisting of elements calculated by applying a function element-wise.
Recommendation: try to use with pure functions whenever possible (produce the same results for same inputs, don't mutate the original collection if possible, nor produce any side effects).
forEach()
This function iterates through all elements of an array too, and applies a function, without returning anything back. Therefore, it can only end a chain of calls, but cannot be used for further chaining.
[1, 2, 3, 4]
.forEach(number => console.info(number));
Recommendation: forEach() is useful when we want to write some code that will result in a side effect per entry in the collection being iterated.
filter()
Filter function uses a predicate is used to sift the wheat from the chaff. The predicate is defining a criteria for the items you want to deal with on the next "stage".
[null, undefined, 0, 1, 2, 3, NaN, "", "You get the idea"]
.filter(Boolean)
.map(filteredElement => filteredElement + "!")
// --> [ "1!", "2!", "3!", "You get the idea!" ]
Recommendation: try to use with pure functions whenever possible. I.e. don't do anything else in filter other than things immediately related to filtration logic itself.
Object.keys() and Object.entries()
These two functions are helpful when we need to iterate over object's keys or key-value pairs, rather than an array's elements.
const targetObject = { a: 1, b: 2, c: 3 };
Object
.keys(targetObject)
.map(key => key + "=" + targetObject[key])
// --> [ "a=1", "b=2", "c=3" ]
same result can be achieved like this
Object
.entries({ a: 1, b: 2, c: 3 })
.map((key, value) => key + "=" + value)
// --> [ "a=1", "b=2", "c=3" ]
Recommendation: you may want to use Object.hasOwnProperty(...) when using working with Object.keys(...). See the documentation for details.
find()
The one is almost trivial. Let's us search for an item that matches a predicate. The search is "left-to-right", and it stops whenever the first "match" is found.
[1, 5, 10, 15]
.find(number >= 7)
// --> 10
findIndex() function can be used when we're looking for a position of an element that matches a predicate.
some() and every()
These functions check whether
a) there is at least one element matching a predicate; or
b) each and every element is matching a predicate.
const arrayOfNumbers = [2, 4, 6, 8, 10];
arrayOfNumbers.every(number => number % 2 === 0); // --> true
arrayOfNumbers.every(number => number % 2 === 1); // --> false
arrayOfNumbers.some(number => number > 1); // --> true
arrayOfNumbers.some(number => number <= 1); // --> false
reduce() and `reduceRight()`
The last one to mention in this quick review is the function that takes a list of things and aggregates it into a single result.
[-1, 0, 1, 2, 3]
.filter(value => value >= 0) // [0, 1, 2, 3]
.map(value => value + 1) // [1, 2, 3, 4]
.reduce((subTotal, currentValue) => subTotal + currentValue, 5);
// --> 15
Recommendation: try to use with pure functions whenever possible.
Universally applicable note on performance. In my benchmarks (don't have them on hand), a hand-written for loop was always faster than forEach, map, and other iterating functions. I do still prefer the functions unless the performance is being severely affected. There two main reasons for that: 1) easier to avoid off-by-one-errors; 2) the code is more readable, since each single function defines an independent step in the data processing flow, thus making code simpler and more maintainable.
I hope, this is an okay overview of some built-in chain-able JavaScript functions. More are described here. Take a look at concat(), sort(), fill(), join(), slice(), reverse() -- I frequently use them too.
If you need something like first() or last(), you will not find them in native functions. Either write your own ones, or use third-party libraries (e.g. lodash, rambda.js).
Here is an example implementation of Array.prototype.forEach:
function foreach(array, cb) {
for (var i = 0; i < array.length; ++i)
cb(array[i], i, array);
}
foreach([2,8,739,9,0], (n, i) =>
console.log("number: %s\nindex: %s\n", n, i));
surely I don't have to spoonfeed you do I?
function array_iterator(array) {
var i = 0;
function next() {
return array[i++];
}
function head() {
return array[i];
}
function tail() {
return array[array.length-1];
}
function more() {
return i < array.length;
}
function done() {
return !more();
}
function reset() {
i = 0;
}
return { next, head, tail, done, more, reset };
}
var nums = [3,34,4];
var iter = array_iterator(nums);
while (iter.more()) {
console.log(iter.next());
}

Sorting a value pair in Javascript

I must be missing the proper term or else I'm sure I could find the answer by searching... in any case, here's what I want to do.
Through javascript, I get four variables (A, B, C, and D) that I would like to sort, and still keep track of the variable name (since it's encoded with meaning information).
Sample Data:
A = 2;
B = 1;
C = 4;
D = 3;
What I need to do now is sort them in value order (4,3,2,1) such that I can actually know the variable name ordering (C,D,A,B).
You can keep an array of value pair objects and then simply sort that array. Of course, the array's sort method need to know how to interpret the object but that can be done by supplying a comparison function to the sort method.
First declare your array of objects:
sample_data = [
{ name: 'A', value: 2 },
{ name: 'B', value: 1 },
{ name: 'C', value: 4 },
{ name: 'D', value: 3 }
];
Then write a comparison function:
function custom_compare (a,b) {
// I'm assuming all values are numbers
return a.value - b.value;
}
Then simply sort and reverse:
sample_data.sort(custom_compare).reverse();
To print out the sorted names simply iterate through the array:
for (var i=0;i<sample_data.length;i++) {
console.log(sample_data[i].name);
}
May it help you:
https://github.com/shinout/SortedList
This is sortedlist library.
I think what you should be looking for something like "Associative arrays" implemented in Javascript.
Check this earlier thread for your answer.

How do I get the difference between an associative array and a regular array in Javascript?

Is it possible to get the difference of an associative array and a regular array in Javascript?
Ex.
array1 = [5, 1, 3];
array2 = [1 => 15, 2 => 20, 3 => 10, 4 => 5, 5 =>50 ];
The difference would be...
diff = [2 => 20, 4=> 5];
I assume your question just had a small typo in your declaration of array2. This is not a big deal.
Anyway, here is a bit of hack, but it gives you what you want:
array1 = [5, 1, 3];
array2 = {1: 15, 2: 20, 3: 10, 4: 5, 5: 50};
var result = {};
for (var i in array2) {
if (array1.indexOf(+i) < 0) {
result[i] = array2[i];
}
}
alert(JSON.stringify(result));
Working example
My hack is the +i in the indexOf call, because the properties of your "associative array" are strings, but your array1 contains numbers. The unary + produces a number from a string. Kind of hackish but it is idiomatic an accepted JavaScript practice.
ADDENDUM
As RobG points out, indexOf is an ES5 method, so if your JavaScript engine is ES3 or below, you will need to implement indexOf on your own. An example of how to do this is at MDN. Alternatively, you can just do the equivalent of indexOf by searching the array on your own.
​
First of all, your second array should be an object and isn't valid JavaScript, as the first two commenters said. Here it is in object form:
var object = { "1": 15, "2": 20, "3": 10, "4": 5, "5": 50 };
This function achieves your desired result:
function findDiff(arr, obj)
{
var tempObj = clone(obj);
for (var i = 0; i < arr.length; i++)
{
var propId = arr[i];
if (tempObj[propId] !== undefined)
delete tempObj[propId];
}
return tempObj;
}
This function relies on a function called clone, which makes sure obj is copied to tempObj by value rather than reference. This prevents the passed object from being modified:
function clone(obj){
if(obj == null || typeof(obj) != 'object')
return obj;
var temp = obj.constructor(); // changed
for(var key in obj)
temp[key] = clone(obj[key]);
return temp;
}
Just call it like this:
var array = [5, 1, 3];
var object = { "1": 15, "2": 20, "3": 10, "4": 5, "5": 50 };
var diff = findDiff(array, object);
You will need to explain in detail what you expect the result of the operation to be.
One interpretation is to remove members from one array based on the values in another, so given:
array1 = [5, 1, 3];
array2 = [15, 20, 10, 5, 50 ];
You might have a function:
function diff(arr1, arr2) {
// Copy arrays so don't affect originals
var t1 = arr1.slice();
var t2 = arr2.slice();
// sort t1
t1.sort();
// Remove members of arr2 from highest indexes to lowest
var i = t1.length;
while (i--) {
t2.splice(t1[i], 1);
}
return t2;
}
alert(diff(array1, array2)); // 15, 10, 50
Note that arrays are zero indexed and there is no 5th member in array2, so the removed values are 20 and 5 (i.e. members with index 1 and 3 respectively).
Another option would be, to do a JSON.stringify() on your variable and check the leftmost or rightmost character of the resulting string. If it is { or }, you have an associative array / object, if [ or ], it is an array. Which I imagine might be a bit costly, depending on the size of your array, but it would do the job.
However... since there is no such thing as a free lunch, and all animals come in pairs, this is only a reasonable solution, if you have used your variable consequently according to your original definition.If you defined an object, like so: obj = [1,2,3] and then, at a later point, added a value such as obj['w'] = 'ww', a JSON.stringify(obj) would only produce [1,2,3], but if you addressed obj['w'] again, you would still get ww, meaning that the value is not forgotten, they just don't mix. Internally, I would imagine, that javascript keeps two separate variable tables, one for objects and one for arrays, and whichever has been defined first, gets the nod when printed with stringify.
And to confuse things still more, if you define a variable as object first, but then add an array key, aka
obj = {1: 11, 2: 22, 3: 33};
obj[4] = 44;
the new key is automatically cast as a string, thus yielding a result in stringify of
{"1":11, "2": 22, "3": 33, "4": 44} //sans the \", for better readibility
Confusing as hell, but I guess that's the price you pay for a little anarchy and ease of use.

How to use underscore.js to produce a flatten result

The json object is
var data = [{"Parent":1,"Child":[4,5,6]},{"Parent":2},{"Parent":3}]
How can I use underscore.js chain/map/pluck etc... function to get the flatten result
var result = [];
for (var i = 0; i < data.length; i++) {
result.push(data[i].Parent);
if (data.Child != undefined) {
for (var j = 0; j < data[i].Child.length; j++) {
result.push(data[i].Child[j]);
}
}
}
console.log(result) >> //1,4,5,6,2,3
Here's a shorter solution:
flat = _.flatten(_.map(data, _.values))
Alternatively, if you want a function that can universally flatten any collection of objects or arrays,
You could extend Underscore with:
_.mixin({crush: function(l, s, r) {return _.isObject(l)? (r = function(l) {return _.isObject(l)? _.flatten(_.map(l, s? _.identity:r)):l;})(l):[];}});
Crush (for lack of a better name) can be called like _.crush(list, [shallow]) or _(list).crush([shallow]) and behaves exactly like a generalized form of Underscore's built-in Flatten.
It can be passed a collection of nested objects, arrays, or both of any depth and will return a single-leveled array containing all of the input's values and own properties. Like Flatten, if it is passed an additional argument which evaluates to true, a "shallow" execution is performed with the output only flattened one level.
Example 1:
_.crush({
a: 1,
b: [2],
c: [3, {
d: {
e: 4
}
}]
});
//=> [1, 2, 3, 4]
Example 2:
_.crush({
a: 1,
b: [2],
c: [3, {
d: {
e: 4
}
}]
}, true);
//=> [1, 2, 3, {
// d: {
// e: 4
// }
// }]
An explanation of the code itself is as follows:
_.mixin({ // This extends Underscore's native object.
crush: function(list, shallow, r) { // The "r" is really just a fancy
// way of declaring an extra variable
// within the function without
// taking up another line.
return _.isObject(list)? // Arrays (being a type of object)
// actually pass this test too.
(r = function(list) { // It doesn't matter that "r" might have
// been passed as an argument before,
// as it gets rewritten here anyway.
return _.isObject(list)? // While this test may seem redundant at
// first, because it is enclosed in "r",
// it will be useful for recursion later.
_.flatten(_.map(list, shallow? // Underscore's .map is different
// from plain Javascript's in
// _.map will always return // that it will apply the passed
// an array, which is why we // function to an object's values
// can then use _.flatten. // as well as those of an array.
_.identity // If "shallow" is truthy, .map uses the identity
// function so "list" isn't altered any further.
: r // Otherwise, the function calls itself on each value.
))
: list // The input is returned unchanged if it has no children.
;
})(list) // The function is both defined as "r" and executed at once.
: [] // An empty array is returned if the initial input
; // was something other than an object or array.
}
});
Hope it helps if anyone needs it. :)
Assuming you want to first get the parents and then get the children:
_.chain(data).pluck("Parent")
.concat(_.flatten(_(data).pluck("Child")))
.reject(_.isUndefined)
.value()
If you want to use underScore.js to flatten an array of many arrays into one array of elements, that's how you do it. Follow my example:
My graph has 2 series. Each series has a name and a sequence of datapoints {xtime, yValue}. My goal is to iron out all the data points from 2 series into one series of data points so to fill out a table.
var reducedArray = // flatten an array of series of data-objects into one series of data-objects
_.flatten( _.map( AllMySeries, function ( aSeries ) {
return ( _.map( aSeries.dataPoints, function ( aPoint ) {
return { curveID: aSeries.legendText, xT: aPoint.x, yVal: aPoint.y };
} ) );
} ) );
My result :
'Series1','2017-04-19 08:54:19',1
'Series1','2017-04-19 08:59:19',0
'Series1','2017-04-19 09:04:19',1
'Series2','2017-04-19 08:54:19',1
'Series2','2017-04-19 08:59:19',0
'Series2','2017-04-19 09:04:19',1

Categories

Resources