sort by number/id within an object in javascript - javascript

is there a way to order these (alal SELECT * FROM this ORDERBY....) in javascript. So if I just wanted to append new list elements to a DOM from an object, but wanted to control the order kind of thing.
var example = [
{id:1, data: { val1: 'val1', val2: 'val2'}, orderById: 313},
{id:2, data: { val1: 'val1', val2: 'val2'}, orderById: 312},
];
var buildString = '';
for ( var i = 0; i < example.length; i++ ) {
// wondering if there is another approach so that i could control the order as I build the string
buildString += "<li class='example-class'>" + example[i].data.val1 + "</li>";
}
$("#some-ul").html('').append(buildString);
so if there is a totally better approach to accomplish this idea I am interested in learning...

Arrays have a method called sort which does exactly as you might expect. It sorts the array. By default, this is done simply by comparing the elements. However, here you are sorting an array of objects, which are normally unsortable. You therefore have to tell the script how to compare the items, like so:
example.sort(function(a,b) {
return a.id - b.id;
});
Your function will be called for each comparison the engine needs to make (varies based on sorting algorithm used interally, doesn't really matter to us). a and b are the elements currently being compared. The function must return:
a negative number if a is to be considered less than b
a positive number if b is to be considered greater than b
zero if the items are to be considered equal.
In this case, I simplified the expression into a.id - b.id. That's because as per basic maths:
if a.id is less than b.id, the result is negative
if a.id is greater than b.id, the result is positive
if they are equal, the result is zero
Hope this helps!

You would use the library Sugar which could do exactly what you are looking for:
http://sugarjs.com/api
[{age:35,name:'ken'},{age:15,name:'bob'}].groupBy(function(n) {
return n.age;
});
{"15":[{"age":15,"name":"bob"}],"35":[{"age":35,"name":"ken"}]}
But as Niet point out, if the only thing you would do is just a basic sort then the native array sort would be fine, but if it is more SQL like functions you search for, then Sugarjs can be great help.
Else http://www.taffydb.com/ would also be a good choice, that would help you great!

Related

Use arrays as keys for a dict

Note:
Asking about alternative methods for performing a task is not a matter of opinion.
Asking about pros and cons of such methods is not a matter of opinion.
This is what I am asking.
Asking which method is preferable, based on such pros and cons, is a matter of opinion.
This is not what I am asking.
I mean to use a dict (or a similar object) in Google apps script, with arrays as keys.
These (I didn't know) are converted to strings when used as dict keys.
The way I wrote my code, for what I needed, was working.
After I added some functionality, the limitations surfaced.
For instance, I want keys to be something like [<color>,<number>].
Then I mean to do
for (key in mydict) {
var c = key[0];
var n = key[1];
... work separately with c as a string and n as a number
}
I guess I could split key at the comma, and convert n to int, but if there is a less cumbersome alternative, I would go for that.
Plus, in a more general case the conversion of key back to its original type may be more involved.
One solution I found is with WeakMap.
I am currently trying it.
Regardless the fact it may work, is there any alternative?
What are possible pros and cons of those other options?
It would be very good to know before rewriting all code.
Use nested objects.
mydict = {
"color1": {
1: <somevalue>,
5: <othervalue>
},
"color2": {
3: <value3>,
10: <value4>
}
};
Then use nested loops:
Object.entries(mydict).forEach(([c, item]) =>
Object.entries(item).forEach([n, value]) => {
// do something with c, n, value
})
);
One simple option is
for (keystr in mydict) {
var key = keystr.split(',');
var c = key[0];
var n = Number(key[1]);
... work separately with c as a string and n as a number
}
which works as long as none of the elements in the keys contain ','.

Iterate through array, add the sum as an object into that Array (lodash)

I'm trying to understand how to iterate through this simple array.
var data = [{"blahh":"hi","blah2":"333","third":"920","fourth":"800"}];
What I am trying to accomplish is, appending an object that is the sum of certain keys (the 'third' and 'fourth')...resulting data being this:
var data = [{"blahh":"hi","blah2":"333","third":"920","fourth":"800", "sum": "1720"}];
I imagine 'lodash' library is capable of neatly accomplishing this. I just can't figure out how to pull that off. I know this is a newbie question but perhaps answering it may helps some soul better understand lodash.
As mentioned - you don't need lodash for this. You're looking at the map function to iterate over an array and return a new array (in this case an array of objects returning a new array with objects that have a sum property) and reduce to iterate over all desired keys and sum their values. For example:
//If you want to treat numbers as numbers then use numbers.
//Some answers here are coercing strings with + - however this will result in NaN on non coerceable strings -ie 'hello',
//which will cause unexpected errors for you later (and typeof NaN is number)
var data = [{"blahh":"hi","blah2":333,"third":920,"fourth":800}];
function returnNewArrayWithSums(keys, array) {
return array.map(obj => {
obj.sum = keys.reduce((sum, key) => typeof obj[key] === 'number' ? obj[key] + sum : sum, 0);
return obj;
});
}
returnNewArrayWithSums(['third', 'fourth'], data);
edited to add - this answer is to give you a use case w/ map/reduce - ideally you wouldn't have to specify numeric keys and make this function more general for any arrays that have objects with k/v pairs that are nums that you want to sum
No need for a library to do this ... the code will likely be more complicated looking than using native methods
data.forEach(item){
item.sum = (+item.third || 0) + (+item.fourth || 0);
});
You have an array of one object - which I dont think you are trying to do. Arrays do not have a key:value pair in them (well actually they do in JavaScript but ignore that). They are an indexed list of values. You probably want to do something like this:
// notice im not putting the integer values in quotes
var data = {'blah':'hi', 'blah2':333, 'third':920, 'fourth':800 };
data.sum = data.third + data.fourth;
That will add a 'sum' field to your object with the value of the sum of third and fourth. Is this what you are trying to do?

Split a JS array into multiple arrays by a comparison function

Here's a pattern I've been reusing in my Javascript a few times, enough that I ended up writing this function for it, using Underscore's groupBy:
var sliceBy = function(array, comparison){
var sliceCounter = 0;
var slices = _(array).groupBy(function(b, i){
var a = array[i - 1];
return i === 0 ? 0 :
sliceCounter += comparison(a, b);
});
return _(slices).values();
};
It iterates through the array, comparing each b value to its previous a value, and determining whether to group b in an array with a or to start a new array. Since groupBy is expecting its iteratee to return a value corresponding to, well, how to group stuff by, I have to use sliceCounter to keep track of this.
Specifically, I'm using this algorithm for two main purposes: to group consecutive points in an array of not-necessarily-consecutive points (i.e b.x === a.x + 1), and to group which paths in an array of SVGs overlap each other.
What I'm worried about is that this feels like a common enough problem that I shouldn't be the first person to write an algorithm for it, yet I haven't been able to find any libraries that provide a function to split an array by a comparison function. My question is:
Is there a CS name for this type of operation, in the same pantheon as map, reduce, filter, sort, etc.?
Is there a more performant way of doing this? (Which is sort of related to question 1, because knowing the answer to that would make it easier to research)

Using underscores sortBy to sort objects

JSON:
[
{ score: 0.648 },
{ score: 0.945 }
]
Javascript:
_.sortBy(array, function(obj){ return obj.score });
However this returns just a copy of the original array. Nothing has changed. I want to sort the array by score in a descending way. Any ideas how to do that?
If you want to sort in descending order, complement the score:
_.sortBy(array, function(obj) { return -obj.score; });
For array sorting in general, outside of the world of Underscore, you can use the native .sort() on the JavaScript Array prototype. It takes two actual elements of the array as parameters, and should return a number less than, equal to, or greater than zero depending on the ordering relationship between the two elements.
In your case, that'd look like:
array.sort(function(o1, o2) {
return -(o1.score - o2.score); // or just return o2.score - o1.score if you like
}
This scheme is far more flexible, because the sort mechanism gives you complete control and makes no assumptions (other than that your comparison function is consistent; if it's not, you get weird behavior).

Javascript: using tuples as dictionary keys

I have a situation where I want to create a mapping from a tuple to an integer. In python, I would simply use a tuple (a,b) as the key to a dictionary,
Does Javascript have tuples? I found that (a,b) in javascript as an expression just returns b (the last item). Apparently this is inherited from C.
So, as a workaround, I thought I can use arrays instead,
my_map[[a,b]] = c
I tried it at the Firebug console and it seemed to work. Is that a good way to do it?
Another alternative I thought of is to create a string out of the tuples
my_map[""+a+":"+b] = c
So the question is: is there any problem with any of these methods? Is there a better way?
EDIT:
Small clarification: in my case, a,b,c are all integers
EcmaScript doesn't distinguish between indexing a property by name or by [], eg.
a.name
is literally equivalent to
a["name"]
The only difference is that numbers, etc are not valid syntax in a named property access
a.1
a.true
and so on are all invalid syntax.
Alas the reason all of these indexing mechanisms are the same is because in EcmaScript all property names are strings. eg.
a[1]
is effectively interpreted as
a[String(1)]
Which means in your example you do:
my_map[[a,b]] = c
Which becomes
my_map[String([a,b])] = c
Which is essentially the same as what your second example is doing (depending on implementation it may be faster however).
If you want true value-associative lookups you will need to implement it yourself on top of the js language, and you'll lose the nice [] style access :-(
You could use my jshashtable and then use any object as a key, though assuming your tuples are arrays of integers I think your best bet is one you've mentioned yourself: use the join() method of Array to create property names of a regular object. You could wrap this very simply:
function TupleDictionary() {
this.dict = {};
}
TupleDictionary.prototype = {
tupleToString: function(tuple) {
return tuple.join(",");
},
put: function(tuple, val) {
this.dict[ this.tupleToString(tuple) ] = val;
},
get: function(tuple) {
return this.dict[ this.tupleToString(tuple) ];
}
};
var dict = new TupleDictionary();
dict.put( [1,2], "banana" );
alert( dict.get( [1,2] ) );
All object keys in Javascript are strings. Using my_map[[a,b]] = c will produce a key in my_map which is the result of [a,b].toString(): a.toString() + ',' + b.toString(). This may actually be desirable (and is similar to your use of a + ':' + b), but you may run into conflicts if your keys contain the separator (either the comma if you use the array as the key, or the colon if you write the string as you have in your example).
Edit: An alternate approach would be to keep a separate array for key references. Eg:
var keys = [
[a,b],
[c,d]
];
var my_map = {
'keys[0]': /* Whatever [a,b] ought to be the key for */,
'keys[1]': /* Whatever [c,d] ought to be the key for */
};
the most simple and "natural" way to achieve something similar is by using multidimensional arrays, like this:
var my_map = [["blah","blah","bla"],
["foo", "bla", 8],
[324, 2345, 235],
[true, false, "whatever..."]];

Categories

Resources