Compare and fill arrays - JS - javascript

a=['a','b','c']
b=['a','c']
I was trying to write a function that compares these both arrays and creates a third array filling the missing array member with null. So the return value should be:
['a',null,'c']
How do I do that?
P.S. Values are always in sequential order.
I am not sharing my try here because I don't want it to be improved or criticized, I know this function is not something hard to write (but it was for me) so I just want answers from experienced people.

You can use the Array.prototype.map function to loop over the a array and replace values.
var a = ['a','b','c'];
var b = ['a','c'];
var c = a.map(function(item) {
return ~b.indexOf(item) ? item : null;
});
console.log(c);
Hint: This only works if a contains at least all of the values that b contains.

A functional, but not necessarily the most efficient, solution:
var results = a.map(function(v) {
return b.indexOf(v) !== -1 ? v : null;
});
As the values are always sequential, it may be more efficient to loop with an index in each array, moving the index forward through b only when a match is found. Whether you actually want to do this as an optimisation depends on how big your arrays are.

Please try the following code,
var result = [];
a.forEach(function(item){
result.push(b.indexOf(item) < 0 ? null : item);
})

A slightly different approach without lookup with indexOf.
var a = ['a', 'b', 'a'],
b = ['a', 'b'],
c = a.map(function () {
var offset = 0;
return function (el, i) {
if (el === b[offset + i]) {
return el;
}
offset--;
return null;
}
}());
document.write('<pre>' + JSON.stringify(c, 0, 4) + '</pre>');

Related

Why is my code pushing every permutation twice?

I'm confused as to why my code is pushing every permutation twice. Please someone help. I'm using heap's algorithm:
var regex = /(.)\1+/g;
function permAlone(str) {
var newArray = str.split('');
var n = newArray.length;
var permutations = [];
var tmp;
function swap(index1, index2) {
tmp = newArray[index1];
newArray[index1] = newArray[index2];
newArray[index2] = tmp;
}
function generate(n, newArray) {
if (n === 1) {
permutations.push(newArray.join(''));
} else {
for(var i = 0; i<n-1; i++) {
generate(n-1, newArray);
swap(n % 2 ? 0 : i, n-1);
permutations.push(newArray.join(''));
}
generate(n-1, newArray);
}
}
generate(n, newArray);
return permutations;
}
permAlone('aab');
The array that is returned is:
["aab", "aab", "aab", "baa", "baa", "aba", "aba", "aba", "baa", "baa"]
So as you can see, the permutations are appearing many more times than intended for each thing. Any help would be great
The code's a little complex and it's difficult to track given the recursion, but if all you want is an array with only unique values, you can simply apply the following code to the result array:
function stripDuplicates(input) {
if (!input || typeof(input) !== 'object' || !('length' in input)) {
throw new Error('input argument is not array.');
}
var newArray = [];
for (var i = 0; i < input.length; i++) {
if (newArray.indexOf(input[i]) === -1) {
newArray.push(input[i]);
}
}
return newArray;
}
This could also be done functionally rather than imperatively, but that's really more of a preference than an optimization issue.
Bálint also points out that you could merely convert the result to a Set, then convert the Set back to an Array, which would automatically strip out any duplicates. Beware, though, that Set is a comparatively new affordance in Javascript and will not function in pre-ES6 environments.
You have a call to:
permutations.push(newArray.join(''));
inside of your for loop. That shouldn't be there. And then, of course if you are permuting strings that have duplicate characters, well, expect to see dupes. e.g., if you permute the string "aa" you'll get two entries from this algorithm "aa" and "aa". Heap's algorithm doesn't try to remove dupes, it treats each element as unique within the string. Obviously, it's trivial to use remove dupes if that's something you care about doing.

Delete the array items which have lower specific value

I want to let array1 transform to array2.
The keyword is the test,test2,885,length.I want the keyword's next value(#?) to the next # is the highest.
var array1=["4#test#4#T#limited","6#test#6#885#restricted","7#test2#2#2#limited","8#test2#4#3#limited","11#885#1#TT#restricted","15#length#1#taw#restricted","17#885#11#T#limited"];
var arrar2=["6#test#6#885#restricted","8#test2#4#3#limited","17#885#11#T#limited","15#length#1#taw#restricted"];
Is this what you want?
var array1=["4#test#4#T#limited","6#test#6#885#restricted","7#test2#2#2#limited","8#test2#4#3#limited","11#885#1#TT#restricted","15#length#1#taw#restricted","17#885#11#T#limited"];
var keywords = ["test","test2","885","length"];
var array2 = [];
keywords.forEach(function (key) {
var matched = [];
var regex = new RegExp("\\b" + key + "#(\\d+)");
array1.forEach(function (value) {
if (regex.test(value)) {
matched.push([parseInt(RegExp.$1), value]);
}
});
if (matched.length > 0) {
matched.sort(function (a, b) {
return b[0] - a[0];
});
array2.push(matched[0][1]);
}
});
alert(array2);
JsFiddle example
You can use underscorejs to filter.
http://underscorejs.org/#filter
Then you can use javascript Array's sort method to sort the array if needed. You can pass a custom sorting function to sort. http://www.w3schools.com/jsref/jsref_sort.asp
The simplest way to "delete items from an array" based on the items fulfilling a condition is to use Array.prototype.filter (with the condition reversed).
In your case, it's rather hard to do because of how you organized your data (bundling it all in a string makes it hard to work with). Here is how i would work around it, but feel free to structure your data better from the start to avoid the awkward conversions:
var array1=["4#test#4#T#limited","6#test#6#885#restricted","7#test2#2#2#limited","8#test2#4#3#limited","11#885#1#TT#restricted","15#length#1#taw#restricted","17#885#11#T#limited"];
Make the data easier to work with by extracting the keyword and the value (i also keep some information to return to the original shape of the array):
var saneData = array1.map(function(item, index){
var split = item.split('#');
return {
keyword : split[1],
value: +split[0],
original : item,
originalIndex : index
}
});
Sort the data by the keyword (so all items with the same keywords go next to each other) and by the values (so the biggest value is first in a subset with the same keywords):
saneData.sort(function(a,b){
if (a.keyword !== b.keyword) {
return a.keyword.localeCompare(b.keyword);
} else {
return b.value - a.value;
}
});
Filter the array, keeping just the first item in a subset with the same keyword:
var filteredData = saneData.filter(function(item, index) {
if (index === 0) return true; // first item is good
return item.keyword !== saneData[index-1].keyword;
});
Return to the original form of the array (with the order preserved):
var array2 = filteredData.sort(function(a,b){ return a.originalIndex - b.originalIndex; }).map(function(item){ return item.original; });
// Result: ["6#test#6#885#restricted", "8#test2#4#3#limited", "15#length#1#taw#restricted", "17#885#11#T#limited"]

how to prevent adding duplicate keys to a javascript array

I found a lot of related questions with answers talking about for...in loops and using hasOwnProperty but nothing I do works properly. All I want to do is check whether or not a key exists in an array and if not, add it.
I start with an empty array then add keys as the page is scrubbed with jQuery.
Initially, I hoped that something simple like the following would work: (using generic names)
if (!array[key])
array[key] = value;
No go. Followed it up with:
for (var in array) {
if (!array.hasOwnProperty(var))
array[key] = value;
}
Also tried:
if (array.hasOwnProperty(key) == false)
array[key] = value;
None of this has worked. Either nothing is pushed to the array or what I try is no better than simply declaring array[key] = value Why is something so simple so difficult to do. Any ideas to make this work?
Generally speaking, this is better accomplished with an object instead since JavaScript doesn't really have associative arrays:
var foo = { bar: 0 };
Then use in to check for a key:
if ( !( 'bar' in foo ) ) {
foo['bar'] = 42;
}
As was rightly pointed out in the comments below, this method is useful only when your keys will be strings, or items that can be represented as strings (such as numbers).
var a = [1,2,3], b = [4,1,5,2];
b.forEach(function(value){
if (a.indexOf(value)==-1) a.push(value);
});
console.log(a);
// [1, 2, 3, 4, 5]
For more details read up on Array.indexOf.
If you want to rely on jQuery, instead use jQuery.inArray:
$.each(b,function(value){
if ($.inArray(value,a)==-1) a.push(value);
});
If all your values are simply and uniquely representable as strings, however, you should use an Object instead of an Array, for a potentially massive speed increase (as described in the answer by #JonathanSampson).
A better alternative is provided in ES6 using Sets. So, instead of declaring Arrays, it is recommended to use Sets if you need to have an array that shouldn't add duplicates.
var array = new Set();
array.add(1);
array.add(2);
array.add(3);
console.log(array);
// Prints: Set(3) {1, 2, 3}
array.add(2); // does not add any new element
console.log(array);
// Still Prints: Set(3) {1, 2, 3}
If you're already using spread...
let colors = ['red', 'orange', 'yellow'];
let moreColors = ['orange', 'green'];
let mergedColors = [...colors, ...moreColors];
and want to avoid duplicates...
let mergedColors = [...colors, ...moreColors.filter(c => !colors.includes(c)) ];
You can try this:
var names = ["Mike","Matt","Nancy","Adam","Jenny","Nancy","Carl"];
var uniqueNames = [];
$.each(names, function(i, el){
if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});
Easiest way to find duplicate values in a JavaScript array
The logic is wrong. Consider this:
x = ["a","b","c"]
x[0] // "a"
x["0"] // "a"
0 in x // true
"0" in x // true
x.hasOwnProperty(0) // true
x.hasOwnProperty("0") // true
There is no reason to loop to check for key (or indices for arrays) existence. Now, values are a different story...
Happy coding
function check (list){
var foundRepeatingValue = false;
var newList = [];
for(i=0;i<list.length;i++){
var thisValue = list[i];
if(i>0){
if(newList.indexOf(thisValue)>-1){
foundRepeatingValue = true;
console.log("getting repeated");
return true;
}
} newList.push(thisValue);
} return false;
}
var list1 = ["dse","dfg","dse"];
check(list1);
Output:
getting repeated
true
let x = "farceus";
let y = "character";
const commonCharacters = function (string1, string2) {
let duplicateCharacter = "";
for (let i = 0; i < string1.length; i += 1) {
if (duplicateCharacter.indexOf(string1[i]) === -1) {
if (string2.indexOf(string1[i]) !== -1) {
duplicateCharacter += string1[i];
}
}
}
return [...duplicateCharacter];
};
console.log(commonCharacters(x, y));

Javascript array sort and unique

I have a JavaScript array like this:
var myData=['237','124','255','124','366','255'];
I need the array elements to be unique and sorted:
myData[0]='124';
myData[1]='237';
myData[2]='255';
myData[3]='366';
Even though the members of array look like integers, they're not integers, since I have already converted each to be string:
var myData[0]=num.toString();
//...and so on.
Is there any way to do all of these tasks in JavaScript?
This is actually very simple. It is much easier to find unique values, if the values are sorted first:
function sort_unique(arr) {
if (arr.length === 0) return arr;
arr = arr.sort(function (a, b) { return a*1 - b*1; });
var ret = [arr[0]];
for (var i = 1; i < arr.length; i++) { //Start loop at 1: arr[0] can never be a duplicate
if (arr[i-1] !== arr[i]) {
ret.push(arr[i]);
}
}
return ret;
}
console.log(sort_unique(['237','124','255','124','366','255']));
//["124", "237", "255", "366"]
You can now achieve the result in just one line of code.
Using new Set to reduce the array to unique set of values.
Apply the sort method after to order the string values.
var myData=['237','124','255','124','366','255']
var uniqueAndSorted = [...new Set(myData)].sort()
UPDATED for newer methods introduced in JavaScript since time of question.
This might be adequate in circumstances where you can't define the function in advance (like in a bookmarklet):
myData.sort().filter(function(el,i,a){return i===a.indexOf(el)})
Here's my (more modern) approach using Array.protoype.reduce():
[2, 1, 2, 3].reduce((a, x) => a.includes(x) ? a : [...a, x], []).sort()
// returns [1, 2, 3]
Edit: More performant version as pointed out in the comments:
arr.sort().filter((x, i, a) => !i || x != a[i-1])
function sort_unique(arr) {
return arr.sort().filter(function(el,i,a) {
return (i==a.indexOf(el));
});
}
How about:
array.sort().filter(function(elem, index, arr) {
return index == arr.length - 1 || arr[index + 1] != elem
})
This is similar to #loostro answer but instead of using indexOf which will reiterate the array for each element to verify that is the first found, it just checks that the next element is different than the current.
Try using an external library like underscore
var f = _.compose(_.uniq, function(array) {
return _.sortBy(array, _.identity);
});
var sortedUnique = f(array);
This relies on _.compose, _.uniq, _.sortBy, _.identity
See live example
What is it doing?
We want a function that takes an array and then returns a sorted array with the non-unique entries removed. This function needs to do two things, sorting and making the array unique.
This is a good job for composition, so we compose the unique & sort function together. _.uniq can just be applied on the array with one argument so it's just passed to _.compose
the _.sortBy function needs a sorting conditional functional. it expects a function that returns a value and the array will be sorted on that value. Since the value that we are ordering it by is the value in the array we can just pass the _.identity function.
We now have a composition of a function that (takes an array and returns a unique array) and a function that (takes an array and returns a sorted array, sorted by their values).
We simply apply the composition on the array and we have our uniquely sorted array.
This function doesn't fail for more than two duplicates values:
function unique(arr) {
var a = [];
var l = arr.length;
for(var i=0; i<l; i++) {
for(var j=i+1; j<l; j++) {
// If a[i] is found later in the array
if (arr[i] === arr[j])
j = ++i;
}
a.push(arr[i]);
}
return a;
};
Here is a simple one liner with O(N), no complicated loops necessary.
> Object.keys(['a', 'b', 'a'].reduce((l, r) => l[r] = l, {})).sort()
[ 'a', 'b' ]
Explanation
Original data set, assume its coming in from an external function
const data = ['a', 'b', 'a']
We want to group all the values onto an object as keys as the method of deduplication. So we use reduce with an object as the default value:
[].reduce(fn, {})
The next step is to create a reduce function which will put the values in the array onto the object. The end result is an object with a unique set of keys.
const reduced = data.reduce((l, r) => l[r] = l, {})
We set l[r] = l because in javascript the value of the assignment expression is returned when an assignment statement is used as an expression. l is the accumulator object and r is the key value. You can also use Object.assign(l, { [r]: (l[r] || 0) + 1 }) or something similar to get the count of each value if that was important to you.
Next we want to get the keys of that object
const keys = Object.keys(reduced)
Then simply use the built-in sort
console.log(keys.sort())
Which is the set of unique values of the original array, sorted
['a', 'b']
The solution in a more elegant way.
var myData=['237','124','255','124','366','255'];
console.log(Array.from(new Set(myData)).sort((a,b) => a - b));
I know the question is very old, but maybe someone will come in handy
A way to use a custom sort function
//func has to return 0 in the case in which they are equal
sort_unique = function(arr,func) {
func = func || function (a, b) {
return a*1 - b*1;
};
arr = arr.sort(func);
var ret = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (func(arr[i-1],arr[i]) != 0)
ret.push(arr[i]);
}
}
return ret;
}
Example: desc order for an array of objects
MyArray = sort_unique(MyArray , function(a,b){
return b.iterator_internal*1 - a.iterator_internal*1;
});
No redundant "return" array, no ECMA5 built-ins (I'm pretty sure!) and simple to read.
function removeDuplicates(target_array) {
target_array.sort();
var i = 0;
while(i < target_array.length) {
if(target_array[i] === target_array[i+1]) {
target_array.splice(i+1,1);
}
else {
i += 1;
}
}
return target_array;
}
I guess I'll post this answer for some variety. This technique for purging duplicates is something I picked up on for a project in Flash I'm currently working on about a month or so ago.
What you do is make an object and fill it with both a key and a value utilizing each array item. Since duplicate keys are discarded, duplicates are removed.
var nums = [1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10];
var newNums = purgeArray(nums);
function purgeArray(ar)
{
var obj = {};
var temp = [];
for(var i=0;i<ar.length;i++)
{
obj[ar[i]] = ar[i];
}
for (var item in obj)
{
temp.push(obj[item]);
}
return temp;
}
There's already 5 other answers, so I don't see a need to post a sorting function.
// Another way, that does not rearrange the original Array
// and spends a little less time handling duplicates.
function uniqueSort(arr, sortby){
var A1= arr.slice();
A1= typeof sortby== 'function'? A1.sort(sortby): A1.sort();
var last= A1.shift(), next, A2= [last];
while(A1.length){
next= A1.shift();
while(next=== last) next= A1.shift();
if(next!=undefined){
A2[A2.length]= next;
last= next;
}
}
return A2;
}
var myData= ['237','124','255','124','366','255','100','1000'];
uniqueSort(myData,function(a,b){return a-b})
// the ordinary sort() returns the same array as the number sort here,
// but some strings of digits do not sort so nicely numerical.
function sort() only is only good if your number has same digit, example:
var myData = ["3","11","1","2"]
will return;
var myData = ["1","11","2","3"]
and here improvement for function from mrmonkington
myData.sort().sort(function(a,b){return a - b;}).filter(function(el,i,a){if(i==a.indexOf(el) & el.length>0)return 1;return 0;})
the above function will also delete empty array and you can checkout the demo below
http://jsbin.com/ahojip/2/edit
O[N^2] solutions are bad, especially when the data is already sorted, there is no need to do two nested loops for removing duplicates. One loop and comparing to the previous element will work great.
A simple solution with O[] of sort() would suffice. My solution is:
function sortUnique(arr, compareFunction) {
let sorted = arr.sort(compareFunction);
let result = sorted.filter(compareFunction
? function(val, i, a) { return (i == 0 || compareFunction(a[i-1], val) != 0); }
: function(val, i, a) { return (i == 0 || a[i-1] !== val); }
);
return result;
}
BTW, can do something like this to have Array.sortUnique() method:
Array.prototype.sortUnique = function(compareFunction) {return sortUnique(this, compareFunction); }
Furthermore, sort() could be modified to remove second element if compare() function returns 0 (equal elements), though that code can become messy (need to revise loop boundaries in the flight). Besides, I stay away from making my own sort() functions in interpreted languages, since it will most certainly degrade the performance. So this addition is for the ECMA 2019+ consideration.
The fastest and simpleness way to do this task.
const N = Math.pow(8, 8)
let data = Array.from({length: N}, () => Math.floor(Math.random() * N))
let newData = {}
let len = data.length
// the magic
while (len--) {
newData[data[len]] = true
}
var array = [2,5,4,2,5,9,4,2,6,9,0,5,4,7,8];
var unique_array = [...new Set(array)]; // [ 2, 5, 4, 9, 6, 0, 7, 8 ]
var uniqueWithSorted = unique_array.sort();
console.log(uniqueWithSorted);
output = [ 0, 2, 4, 5, 6, 7, 8, 9 ]
Here, we used only Set for removing duplicity from the array and then used sort for sorting array in ascending order.
I'm afraid you can't combine these functions, ie. you gotta do something like this:-
myData.unique().sort();
Alternatively you can implement a kind of sortedset (as available in other languages) - which carries both the notion of sorting and removing duplicates, as you require.
Hope this helps.
References:-
Array.sort
Array.unique

(Deep) copying an array using jQuery [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the most efficient way to clone a JavaScript object?
I need to copy an (ordered, not associative) array of objects. I'm using jQuery. I initially tried
jquery.extend({}, myArray)
but, naturally, this gives me back an object, where I need an array (really love jquery.extend, by the way).
So, what's the best way to copy an array?
Since Array.slice() does not do deep copying, it is not suitable for multidimensional arrays:
var a =[[1], [2], [3]];
var b = a.slice();
b.shift().shift();
// a is now [[], [2], [3]]
Note that although I've used shift().shift() above, the point is just that b[0][0] contains a pointer to a[0][0] rather than a value.
Likewise delete(b[0][0]) also causes a[0][0] to be deleted and b[0][0]=99 also changes the value of a[0][0] to 99.
jQuery's extend method does perform a deep copy when a true value is passed as the initial argument:
var a =[[1], [2], [3]];
var b = $.extend(true, [], a);
b.shift().shift();
// a is still [[1], [2], [3]]
$.extend(true, [], [['a', ['c']], 'b'])
That should do it for you.
I realize you're looking for a "deep" copy of an array, but if you just have a single level array you can use this:
Copying a native JS Array is easy. Use the Array.slice() method which creates a copy of part/all of the array.
var foo = ['a','b','c','d','e'];
var bar = foo.slice();
now foo and bar are 5 member arrays of 'a','b','c','d','e'
of course bar is a copy, not a reference... so if you did this next...
bar.push('f');
alert('foo:' + foo.join(', '));
alert('bar:' + bar.join(', '));
you would now get:
foo:a, b, c, d, e
bar:a, b, c, d, e, f
Everything in JavaScript is pass by reference, so if you want a true deep copy of the objects in the array, the best method I can think of is to serialize the entire array to JSON and then de-serialize it back.
If you want to use pure JavaScript then try this:
var arr=["apple","ball","cat","dog"];
var narr=[];
for(var i=0;i<arr.length;i++){
narr.push(arr[i]);
}
alert(narr); //output: apple,ball,vat,dog
narr.push("elephant");
alert(arr); // output: apple,ball,vat,dog
alert(narr); // apple,ball,vat,dog,elephant
how about complex types?
when array contains objects... or any else
My variant:
Object.prototype.copy = function(){
var v_newObj = {};
for(v_i in this)
v_newObj[v_i] = (typeof this[v_i]).contains(/^(array|object)$/) ? this[v_i].copy() : this[v_i];
return v_newObj;
}
Array.prototype.copy = function(){
var v_newArr = [];
this.each(function(v_i){
v_newArr.push((typeof v_i).contains(/^(array|object)$/) ? v_i.copy() : v_i);
});
return v_newArr;
}
It's not final version, just an idea.
PS: method each and contains are prototypes also.
I've come across this "deep object copy" function that I've found handy for duplicating objects by value. It doesn't use jQuery, but it certainly is deep.
http://www.overset.com/2007/07/11/javascript-recursive-object-copy-deep-object-copy-pass-by-value/
I plan on releasing this code in the next version of jPaq, but until then, you can use this if your goal is to do a deep copy of arrays:
Array.prototype.clone = function(doDeepCopy) {
if(doDeepCopy) {
var encountered = [{
a : this,
b : []
}];
var item,
levels = [{a:this, b:encountered[0].b, i:0}],
level = 0,
i = 0,
len = this.length;
while(i < len) {
item = levels[level].a[i];
if(Object.prototype.toString.call(item) === "[object Array]") {
for(var j = encountered.length - 1; j >= 0; j--) {
if(encountered[j].a === item) {
levels[level].b.push(encountered[j].b);
break;
}
}
if(j < 0) {
encountered.push(j = {
a : item,
b : []
});
levels[level].b.push(j.b);
levels[level].i = i + 1;
levels[++level] = {a:item, b:j.b, i:0};
i = -1;
len = item.length;
}
}
else {
levels[level].b.push(item);
}
if(++i == len && level > 0) {
levels.pop();
i = levels[--level].i;
len = levels[level].a.length;
}
}
return encountered[0].b;
}
else {
return this.slice(0);
}
};
The following is an example of how to call this function to do a deep copy of a recursive array:
// Create a recursive array to prove that the cloning function can handle it.
var arrOriginal = [1,2,3];
arrOriginal.push(arrOriginal);
// Make a shallow copy of the recursive array.
var arrShallowCopy = arrOriginal.clone();
// Prove that the shallow copy isn't the same as a deep copy by showing that
// arrShallowCopy contains arrOriginal.
alert("It is " + (arrShallowCopy[3] === arrOriginal)
+ " that arrShallowCopy contains arrOriginal.");
// Make a deep copy of the recursive array.
var arrDeepCopy = arrOriginal.clone(true);
// Prove that the deep copy really works by showing that the original array is
// not the fourth item in arrDeepCopy but that this new array is.
alert("It is "
+ (arrDeepCopy[3] !== arrOriginal && arrDeepCopy === arrDeepCopy[3])
+ " that arrDeepCopy contains itself and not arrOriginal.");
You can play around with this code here at JS Bin.

Categories

Resources