Differences between js objects - javascript

I got the following problem and I am looking for a really efficient way to do this.
I got two Javascript Objects always build like {id:data,id:data,..}
If I only look on the Keys they will look like this:
B = ["1","2","3"]
A = ["2","3","4"]
Now I need the information what i need to do, to transform B into A, so in this case: Delete B.1 and B.4 = A.4 .
I was thinking that maybe a prototyp function for Object would be a good way to do this.
This is what i have so far:
Array.prototype.diff = function(a) {
return this.filter(function(i) {return a.indexOf(i) < 0;});
};
Object.prototype.syncTo = function(b,callbackA,callbackB){
var a = this;
var bKeys = Object.keys(b);
var aKeys = Object.keys(a);
var toremove = bKeys.diff(aKeys);
var toadd = aKeys.diff(bKeys);
for(var i = 0; i < toremove.length; i++) {
if(b.hasOwnProperty(toremove[i])) {
delete b[toremove[i]];
}
}
callbackB(b);
for(var i = 0; i < toadd.length; i++) {
if(a.hasOwnProperty(toadd[i])){
<<Dont know how to go on now>>
}
}
callbackA(XXXXXX);
};
Where CallbackA should be called with all elements that have to be added to B and CallbackB should be called with all elements that need to be removed from B.
I am struggling With the elements for callbackA and in general whether this is an efficient way of doing this.
Thank you for your support !
EDIT:
An Example for one of the Callbacks would be :
callbackB:
function (items){
for(var i in items){
items[i].removeSomeWhereElse();
}
}

There are a couple of libraries that can do this if your search NPM, as a shameless plug I'll just mention one I authored that diffs any object, including array insertion/deletion/moves:
https://github.com/benjamine/jsondiffpatch
here's the DEMO page diffing 2 arrays, as you need:
http://benjamine.github.io/jsondiffpatch/demo/index.html?desc=moving%20around&left=%5B0%2C1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%5D&right=%5B10%2C0%2C1%2C7%2C2%2C4%2C5%2C6%2C88%2C9%2C3%5D
you can see deletes, adds, and even moves (move detection can be disabled by configuration if you want)
Using library will be the more efficient in saving your time, now if you want to save CPU cycles instead, you could just use a simple implementation of LCS (which is the standard algorithm to solve to the problem you're describing), see: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
jsondiffpatch includes that (for js), and you can steal it from here: https://github.com/benjamine/jsondiffpatch/blob/master/src/filters/lcs.js

Related

Compare two lists and remove common elements using angular js

I am having 2 lists like below
list1 =
['option1','option2','option3','option4','option5','option6','option7'];
list2 = ['option3', 'option4', 'option7'];
I want the list to be
listFinal = ['option1','option2','option5','option6','option7'];
Please give me the suggestion using angular js how to solve this using filter
Tried to use this code to solve this using filter but unable to succeed.
app.filter('unique', function() {
return function(collection, keyname) {
var output = [],
keys = [];
angular.forEach(collection, function(item) {
var key = item[keyname];
if(keys.indexOf(key) === -1) {
keys.push(key);
output.push(item);
}
});
return output;
};
});
I'm not sure that you really want a filter here. This is something that you should probably solve outside of Angular. If you're willing to add lodash to your project, you could do this:
var diff = _.difference(array1, array2);
If you must use a filter, you could try something like this?
app.filter('difference', function() {
return function(input, diff_array) {
var result = [];
for (var i = 0; i < input.length; i++) {
if (diff_array.indexOf(input[i]) == -1) {
result.push(input[i]);
}
}
return result;
}
}
Note that if you do this, your template has to look something like:
{{ input | difference:diff_arr }}
I haven't actually tested any of this, but this should be the general idea. I concur with Phillip that this really isn't something you should try to solve in Angular.
What you are describing is an "array/set difference". There are many questions on StackOverflow asking about this already. This is not related to Angular.js, but is an problem with an algorithmic solution. Just to add bit of interesting material, a "naive" solution runs in O(nlogn) which would be:
Sort the two lists/arrays from lowests to highest
Traverse each array setting the internal pointer to 0 initially, compare the elements. If the element in Array A is larger than the on in Array B advance the pointer by 1 in Array B, else B, else if they are equal, remove the result from the array and advance both pointers
What is the fastest or most elegant way to compute a set difference using Javascript arrays?
JavaScript array difference

How to you use recursion in javascript to create key value objects

I understand how to go about tasks using loops, recursion is kind of a mystery to me, but from what I understand in certain cases it can save a ton of time if looping through a lot of data.
I created the following function to loop through a large(ish) data set.
var quotes = require('./quotes.js');
//Pulls in the exported function from quotes.js
var exportedQuotes = quotes.allQuotes();
var allAuthors = exportedQuotes.author;
//Create an empty key value object, we use these to coerce unique values to an array
var uniqs = {};
//I create this object to hold all the authors and their quotes
var fullQuote = {};
//Create an object with only unique authors
for(var i = 0; i < allAuthors.length ; i++){
fullQuote[allAuthors[i]] = null;
}
//Coerce unique authors from javascript object into an array
var uniqAuthors = Object.keys(uniqs);
var quoteCount = exportedQuotes.author.length;
var iterativeSolution = function(){
for(var i = 0; i < Object.keys(fullQuote).length; i++){
for(var j = 0; j < exportedQuotes.author.length; j++){
//If the author in the unique list is equal to the author in the duplicate list
if(Object.keys(fullQuote)[i] == exportedQuotes.author[j]){
//if an author has not had a quote attributed to its name
if(fullQuote[exportedQuotes.author[j]] == null){
//assign the author an array with the current quote at the 0 index
fullQuote[exportedQuotes.author[j]] = [exportedQuotes.quote[j]]
} else {
//if an author already has a quote assigned to its name then just add the current quote to the authors quote list
fullQuote[exportedQuotes.author[j]].push(exportedQuotes.quote[j])
}
}
}
}
}
I don't currently have the skills to do analyze this, but, I'm wondering if there is a case for recursion to save the time it takes to get through all the loops. And if there is a case for recursion what does it look like for nested loops in javascript, specifically when creating key value objects recursively?
There may be a slight misunderstanding about what recursion is: recursion does not save time. It's just a different way of doing the same traversal. It generally a little easier to read, and depending on the problem, will map to certain algorithms better. However, one of the first things we do when we need to start optimizing code for speed is to remove recursion, turning them back into loops, and then even "unrolling" loops, making code much uglier, but fast, in the process. Recursion vs plain loops is almost always a matter of taste. One looks nicer, but that's hardly the only quality we should judge code on.
And also: just because it sounds like I'm advocating against using it, doesn't mean you shouldn't just try it: take that code, put it in a new file, rewrite that file so that it uses recursion. Doing so lets you compare your code. Which one is faster? Which is easier to read? Now you know something about how (your) code behaves, and you'll have learned something valuable.
Also don't sell yourself short: if you wrote this code, you know how it works, so you know how to analyze it enough to rewrite it.
Algorithms makes code fast or slow, not recursion. Some quite fast algorithms can use recursion, but that's a whole different story. Many algorithms can be written as both with recursion, and without recursion.
However, your code has a big problem. Notice how many times you call this code?
Object.keys(fullQuote)
You are re-computing the value of that many many times in your code. Don't do that. Just call it once and store in a variable, like the following:
var uniqAuthors = Object.keys(uniqs);
var uniqFullQuote = Object.keys(fullQuote);
var quoteCount = exportedQuotes.author.length;
//Loop through all quotes and assign all quotes to a unique author::Each author has many quotes
for(var i = 0; i < uniqFullQuote.length; i++){
for(var j = 0; j < exportedQuotes.author.length; j++){
//If the author in the unique list is equal to the author in the duplicate list
if(uniqFullQuote[i] == exportedQuotes.author[j]){
//if an author has not had a quote attributed to its name
if(fullQuote[exportedQuotes.author[j]] == null){
//assign the author an array with the current quote at the 0 index
fullQuote[exportedQuotes.author[j]] = [exportedQuotes.quote[j]]
} else {
//if an author already has a quote assigned to its name then just add the current quote to the authors quote list
fullQuote[exportedQuotes.author[j]].push(exportedQuotes.quote[j])
}
}
}
}
You don't have to iterate Object.keys(fullQuote).
var quotes = require('./quotes.js'),
exportedQuotes = quotes.allQuotes(),
allAuthors = exportedQuotes.author,
fullQuote = Object.create(null);
for(var i=0; i < allAuthors.length; ++i)
(fullQuote[allAuthors[i]] = fullQuote[allAuthors[i]] || [])
.push(exportedQuotes.quote[i])
I don't recommend recursion. It won't improve the asymptotic cost, and in JS calling functions is a bit expensive.
I got really curious and created a recursive solution just to see how it works. Then timed it, my iterative solution took 53 seconds to run, while my recursive solution took 1 millisecond to run. The iterative approach can obviously be tweaked based on the answers provided below, to run faster, but a recursive approach forced me to think in a "leaner" manner when creating my function.
var exportedQuotes = quotes.allQuotes();
var allAuthors = exportedQuotes.author;
var n = allAuthors.length
var fullQuote = {};
var recursiveSolution = function(arrayLength) {
//base case
if(arrayLength <= 1){
if(fullQuote[exportedQuotes.author[0]] == null){
fullQuote[exportedQuotes.author[0]] = [exportedQuotes.quote[0]];
}else{
fullQuote[exportedQuotes.author[0]].push(exportedQuotes.quote[0])
}
return;
};
//recursive step
if(fullQuote[exportedQuotes.author[arrayLength]] == null){
fullQuote[exportedQuotes.author[arrayLength]] = [exportedQuotes.quote[arrayLength]];
}else{
fullQuote[exportedQuotes.author[arrayLength]].push(exportedQuotes.quote[arrayLength])
}
newLength = arrayLength - 1;
return recursiveSolution(newLength);
}
////////Timing functions
var timeIteration = function(){
console.time(iterativeSolution);
iterativeSolution(); // run whatever needs to be timed in between the statements
return console.timeEnd(iterativeSolution);
}
var timeRecursive = function(){
console.time(recursiveSolution(n));
recursiveSolution(n); // run whatever needs to be timed in between the statements
return console.timeEnd(recursiveSolution(n));
}

Is this as fast as JS array copy can get without loop unrolling?

This is related to this question.
I have heard that the while pattern with a decrement and a greater than test is faster than any other loop pattern. Given that, is this the fastest possible array copy in js?
function arrayCopy(src,sstart,dst,dstart,length) {
length += sstart;
dstart += length;
while(--length >= sstart) {
dst[--dstart] = src[length];
}
}
Other test functions
function slowCopy(src,sstart,dst,dstart,length) {
for(var i = sstart; i < sstart+length;i+=1 ) {
dst[dstart++] = src[i];
}
}
function aCopy(src,sstart,dst,dstart,length) {
Array.prototype.splice.apply(dst,[dstart, length].concat(src.slice(sstart,sstart+length)));
}
Test Results http://jsperf.com/fastest-js-arraycopy
arrayCopy -
2,899
±5.27%
fastest
slowCopy - WINNER
2,977
±4.86%
fastest
aCopy -
2,810
±4.61%
fastest
I want to add some more of the suggested functions below to the jsPerf tests but none of them incorporate source start offset, destination start offset or length of copy. Anyway, I was somewhat surprised by these results which appear to be the opposite of what I expect
Who says you need a loop?
var myArrayCopy = JSON.parse(JSON.stringify(myArray));
This method makes a deep clone of the array. Here it is in a function:
function arrayCopy(src,sstart,dst,dstart,length) {
dst = JSON.parse(JSON.stringify(src));
}
Keep in mind the other variables (besides src and dst) are there just to maintain your original code structure in case you have pre-existing calls to this function. They won't be used and can be removed.
Slow Copy is, surprisingly, the winner. By a narrow margin:
function slowCopy(src,sstart,dst,dstart,length) {
for(var i = sstart; i < sstart+length;i+=1 ) {
dst[dstart++] = src[i];
}
}
I think this is the fastest way:
var original = [1, 2, 3];
var copy = original.slice(0);

Can I select 2nd element of a 2 dimensional array by value of the first element in Javascript?

I have a JSON response like this:
var errorLog = "[[\"comp\",\"Please add company name!\"],
[\"zip\",\"Please add zip code!\"],
...
Which I'm deserializing like this:
var log = jQuery.parseJSON(errorLog);
Now I can access elements like this:
log[1][1] > "Please add company name"
Question:
If I have the first value comp, is there a way to directly get the 2nd value by doing:
log[comp][1]
without looping through the whole array.
Thanks for help!
No. Unless the 'value' of the first array (maybe I should say, the first dimension, or the first row), is also it's key. That is, unless it is something like this:
log = {
'comp': 'Please add a company name'
.
.
.
}
Now, log['comp'] or log.comp is legal.
There are two was to do this, but neither avoids a loop. The first is to loop through the array each time you access the items:
var val = '';
for (var i = 0; i < errorLog.length; i++) {
if (errorLog[i][0] === "comp") {
val = errorLog[i][1];
break;
}
}
The other would be to work your array into an object and access it with object notation.
var errors = {};
for (var i = 0; i < errorLog.length; i++) {
errors[errorLog[i][0]] = errorLog[i][1];
}
You could then access the relevant value with errors.comp.
If you're only looking once, the first option is probably better. If you may look more than once, it's probably best to use the second system since (a) you only need to do the loop once, which is more efficient, (b) you don't repeat yourself with the looping code, (c) it's immediately obvious what you're trying to do.
No matter what you are going to loop through the array somehow even it is obscured for you a bit by tools like jQuery.
You could create an object from the array as has been suggested like this:
var objLookup = function(arr, search) {
var o = {}, i, l, first, second;
for (i=0, l=arr.length; i<l; i++) {
first = arr[i][0]; // These variables are for convenience and readability.
second = arr[i][1]; // The function could be rewritten without them.
o[first] = second;
}
return o[search];
}
But the faster solution would be to just loop through the array and return the value as soon as it is found:
var indexLookup = function(arr, search){
var index = -1, i, l;
for (i = 0, l = arr.length; i<l; i++) {
if (arr[i][0] === search) return arr[i][1];
}
return undefined;
}
You could then just use these functions like this in your code so that you don't have to have the looping in the middle of all your code:
var log = [
["comp","Please add company name!"],
["zip","Please add zip code!"]
];
objLookup(log, "zip"); // Please add zip code!
indexLookup(log, "comp"); // Please add company name!
Here is a jsfiddle that shows these in use.
Have you looked at jQuery's grep or inArray method?
See this discussion
Are there any jquery features to query multi-dimensional arrays in a similar fashion to the DOM?

What's a good JavaScript pattern for categorizing things into types?

I'm looking for a way (in JavaScript) to collect a set of objects into multiple arrays, where each array contains a certain type of object, and the arrays are stored as values in an associative array, with the keys being the types. For example:
Input:
[<apple>, <cat>, <pear>, <mercedes>, <dog>, <ford>, <orange>]
Output:
{
'fruit': [<apple>, <pear>, <orange>],
'animal': [<cat>, <dog>],
'car': [<mercedes>, <ford>]
}
In ruby, you could do the following:
things_by_type = {}
things.each do |thing|
(things_by_type[thing.type] ||= []) << thing
end
which is nice and concise.
What's a good pattern for doing the same thing in JavaScript that's concise and efficient? I could do something like this, but it's not as nice:
var thing, things_by_type = {};
for (var i = 0; i < things.length; i++) {
thing = things[i];
if(things_by_type[thing.type]) {
things_by_type[thing.type].push(thing);
} else {
things_by_type[thing.type] = [thing];
}
}
I'm not sure if it's a good pattern, but it's similar to your ruby sample:
var things_by_type = {};
for (var i in things) {
var thing = things[i];
(things_by_type[thing.type] || (things_by_type[thing.type] = [])).push(thing);
}
And if you can assume Javascript 1.6:
var things_by_type = {};
things.forEach(function(thing) {
(things_by_type[thing.type] || (things_by_type[thing.type] = [])).push(thing);
})
In ruby, you could do the following:
things_by_type = {}
things.each do |thing|
(things_by_type[thing.type] ||= []) << thing
end
which is nice and concise.
Actually, you can make that even nicer.
First off, Hash.new takes a block argument which will be called every time a non-existing key is referenced. You can use that to create that key. That way you get rid of the conditional logic inside the block.
things_by_type = Hash.new {|h, k| h[k] = [] }
things.each do |thing|
things_by_type[thing.type] << thing
end
Secondly, what you have here is called a fold or reduce: you are "folding" or "reducing" a collection (the array of objects) into a single value (the hash, which confusingly also happens to be a collection, but is nonetheless a single value).
You can generally easily spot this pattern by looking for places where you initialize some variable, then loop over a collection and manipulate that variable at every iteration of the loop.
Ruby has folding built in, via the Enumerable#reduce method:
things.reduce(Hash.new {|h, k| h[k] = [] }) do |h, thing|
h.tap { h[thing.type] << thing }
end
But what you are really doing, is grouping the array by the type attribute of its elements, which is also built into Ruby as Enumerable#group_by:
things.group_by {|thing| thing.type }
Which can be further simplified by using Symbol#to_proc to
things.group_by(&:type)
Unfortunately, ECMAScript doesn't have groupBy, nor default values for non-existing properties, but it does have Array.prototype.reduce:
things.reduce(function (acc, thing) {
(acc[thing.type] || (acc[thing.type] = [thing])).push(thing);
return acc;
}, {});
almost the same code, but works a bit different, you can use the fancy set function easier and it separates logic:
var a = {set:function(type,thing){
if (this[type]) {
this[type].push(thing);
} else {
this[type] = [thing];
}
}};
a.set('a',0);
a.set('b',1);
a.set('a',2);

Categories