Related
I have a function for search the longest common elements in two array:
/**
* Return the common elements in two array
*/
function searchArrayInArray(array1, array2) {
var result = [];
for (var j = 0, e = array1.length; j < e; j++){
var element = array1[j];
if( array2.indexOf(element) !== -1 ){
result.push(element);
}
}
return result;
}
This method works, but I want improve performance because I call it many times.
There is any performance improvement appliable?
Side note: the elements into the arrays are unsorted string
/**
* Return the common elements in two array
*/
function searchArrayInArray(array1, array2) {
var result = [];
for (var j = 0, e = array1.length; j < e; j++){
var element = array1[j];
if( array2.indexOf(element) !== -1 ){
result.push(element);
}
}
return result;
}
var result = searchArrayInArray(['a', 'b'], ['b', 'c']);
document.getElementById("result").innerHTML = JSON.stringify(result, null, 2);
<pre id="result"></pre>
If you're concerned about performance, you'll want to use a data structure which provides good look-up times. Array methods like Array.prototype.indexOf, Array.prototype.includes, and Array.prototype.find all have linear look-ups. Map has binary look-up and Set has constant look-up. I think Set will be ideal in this situation.
A straightforward implementation of intersection -
const intersection = (a1 = [], a2 = []) =>
{ const s =
new Set(a1)
const result =
[]
for (const x of a2)
if (s.has(x))
result.push(x)
return result
}
console.log(intersection(['a', 'b'], ['b', 'c']))
// [ 'b' ]
This can be simplified a bit using higher-order functions like Array.prototype.filter -
const intersection = (a1 = [], a2 = []) =>
{ const s =
new Set(a1)
return a2.filter(x => s.has(x))
}
console.log(intersection(['a', 'b'], ['b', 'c']))
// [ 'b' ]
This concept can be expanded upon to support intersecting an arbitrary number of arrays -
const intersection = (a1 = [], a2 = []) =>
{ const s =
new Set(a1)
return a2.filter(x => s.has(x))
}
const intersectAll = (a = [], ...more) =>
more.reduce(intersection, a)
console.log(intersectAll(['a', 'b'], ['b', 'c'], ['b', 'd'], ['e', 'b']))
// [ 'b' ]
Well indexOf() is O(n) so by using Set() instead you can improve complexity from O(n^2) to O(n * log n)
function searchArrayInArray(array1, array2) {
var result = [];
let set = new Set();
for(el of array2){
set.add(el);
}
for (var j = 0, e = array1.length; j < e; j++){
var element = array1[j];
if( set.has(element) ){
result.push(element);
}
}
return result;
}
The easiest way:
var a = [1,2,3,4,5,6,7,8,9,10];
var b = [2,4,5,7,11,15];
var c = a.filter(value => b.includes(value))
console.log(c)
This question already has answers here:
Merge two arrays with alternating values
(14 answers)
Closed 4 years ago.
I found this question but it is closed, author narrowed it to jQuery, and answers are only for case when two arrays has equal size.
So my question is how to merge two arbitrary arrays where elements alternate? (in answer provide function m(a,b) which take two arrays a and b and return merged array)
Test cases:
var as = [1,2,3];
var am = [1,2,3,4,5];
var al = [1,2,3,4,5,6,7];
var b = ["a","b","c","d","e"];
var m = (a,b) => "...magic_here...";
m(as,b); // -> [1,"a",2,"b",3,"c","d","e"]
m(am,b); // -> [1,"a",2,"b",3,"c",4,"d",5,"e"]
m(al,b); // -> [1,"a",2,"b",3,"c",4,"d",5,"e",6,7]
You can travel all elements and add it to result.
const as = [1, 2, 3];
const am = [1, 2, 3, 4, 5];
const al = [1, 2, 3, 4, 5, 6, 7];
const b = ["a", "b", "c", "d", "e"];
function m(a, b) {
const l = Math.max(a.length, b.length);
const result = [];
for (let i = 0; i < l; i++) {
if (a[i] !== undefined) {
result.push(a[i]);
}
if (b[i] !== undefined) {
result.push(b[i]);
}
}
console.log(result);
return result;
}
m(as, b); // -> [1,"a",2,"b",3,"c","d","e"]
m(am, b); // -> [1,"a",2,"b",3,"c",4,"d",5,"e"]
m(al, b); // -> [1,"a",2,"b",3,"c",4,"d",5,"e",6,7]
A very simple is to loop over and check if value exists. If yes, push else continue.
Solution 1
function alternateMerge(a1, a2) {
var length = Math.max(a1.length, a2.length);
var output = [];
for(var i = 0; i< length; i++) {
if (!!a1[i]) {
output.push(a1[i])
}
if (!!a2[i]) {
output.push(a2[i])
}
}
return output;
}
var as = [1,2,3];
var am = [1,2,3,4,5];
var al = [1,2,3,4,5,6,7];
var b = ["a","b","c","d","e"];
console.log(alternateMerge(as, b).join())
console.log(alternateMerge(am, b).join())
console.log(alternateMerge(al, b).join())
Solution 2
function alternateMerge(a1, a2) {
const arr = a1.length > a2.length ? a1 : a2;
return arr.reduce((acc, _, i) => {
!!a1[i] && acc.push(a1[i]);
!!a2[i] && acc.push(a2[i]);
return acc;
}, [])
}
var as = [1,2,3];
var am = [1,2,3,4,5];
var al = [1,2,3,4,5,6,7];
var b = ["a","b","c","d","e"];
console.log(alternateMerge(as, b).join())
console.log(alternateMerge(am, b).join())
console.log(alternateMerge(al, b).join())
You can use array#concat with spread syntax to generate the array merged alternatively.
var m = (a,b) => {
const minLen = Math.min(a.length, b.length);
return [].concat(...a.slice(0, minLen).map((v,i) => [v, b[i]]), a.slice(minLen, a.length), b.slice(minLen, b.length));
};
var as = [1,2,3];
var am = [1,2,3,4,5];
var al = [1,2,3,4,5,6,7];
var b = ["a","b","c","d","e"];
console.log(m(as,b)); // -> [1,"a",2,"b",3,"c","d","e"]
console.log(m(am,b)); // -> [1,"a",2,"b",3,"c",4,"d",5,"e"]
console.log(m(al,b)); // -> [1,"a",2,"b",3,"c",4,"d",5,"e",6,7]
You can do:
const as = [1,2,3];
const am = [1,2,3,4,5];
const al = [1,2,3,4,5,6,7];
const b = ["a","b","c","d","e"];
const m = (a, b) => (a.length > b.length ? a : b)
.reduce((acc, cur, i) => a[i] && b[i] ? [...acc, a[i], b[i]] : [...acc, cur], []);
console.log(m(as,b)); // -> [1,"a",2,"b",3,"c","d","e"]
console.log(m(am,b)); // -> [1,"a",2,"b",3,"c",4,"d",5,"e"]
console.log(m(al,b)); // -> [1,"a",2,"b",3,"c",4,"d",5,"e",6,7]
.as-console-wrapper { max-height: 100% !important; top: 0; }
Given an array of paired integers, HOW can I group by intersections. Does anyone have a simple function that could convert my input, into the desired output?
Input
var in = ["0:3", "1:3", "4:5", "5:6", "6:8"]
Desired output
[
[0, 1, 3],
[4, 5, 6, 8]
]
UPDATE:
#apsiller asked my question in the comments more clearly then I originally posted:
"Considering each number as a node in a graph, and each pairing x:y as an edge between nodes x and y, find the sets of numbers that can be traveled to using the edges defined. That is, in graph theory terms, find the distinct connected components within such a graph.
For instance, there is no way to travel from 4 to 0 so they are in different groups, but there is a way to travel from 1 to 0 (by way of 3) so they are in the same group."
To reiterate the desired output is a grouping of transversable nodes, based on a potentially random input set.
Thanks everyone. Given everyones input I was able to find a similar question on here that led me my answer. Finding All Connected Components of an Undirected Graph
The first step was to change my input to groups of pairs.
var input = [
[0, 3],
[1, 3],
[4, 5],
[5, 6],
[6, 8]
]
The next step was to use whats called Breadth-first search
function breadthFirstSearch(node, nodes, visited) {
var queue = [];
var group = [];
var pair = null;
queue.push(node);
while (queue.length > 0) {
node = queue.shift();
if (!visited[node]) {
visited[node] = true;
group.push(node);
for (var i = 0, len = nodes.length; i < len; i++) {
pair = nodes[i];
if (pair[0] === node && !visited[pair[1]]) {
queue.push(pair[1]);
} else if (pair[1] === node && !visited[pair[0]]) {
queue.push(pair[0]);
}
}
}
}
return group;
};
function groupReachableVertices(input) {
var groups = [];
var visited = {};
for (var i = 0, len = input.length; i < len; i += 1) {
var current_pair = input[i];
var u = current_pair[0];
var v = current_pair[1];
var src = null;
if (!visited[u]) {
src = u;
} else if (!visited[v]) {
src = v;
}
if (src) {
groups.push(breadthFirstSearch(src, input, visited));
}
}
return groups;
};
Putting it all together...
var output = groupReachableVertices(input);
[
[0, 1, 3],
[4, 5, 6, 8]
]
You could do something like this.
function group(data) {
var r = [[]],c = 0,a = [0]
var d = data.map(e => e.split(':').sort((a, b) => a - b)).sort((a, b) => a[0] - b[0])
d.forEach(function(e, i) {
if (e[0] > a[a.length - 1]) {
r.push(e)
a.push(e[1])
c++
} else {
r[c] = r[c].concat(e)
a[a.length - 1] = e[1]
}
})
return r.map(e => [...new Set(e)].sort((a, b) => a - b))
}
var test1 = ["0:3", "1:3", "4:5", "5:6", "6:8"]
var test2 = ["0:3", "1:3", "4:5", "9:11", "10:12", '3:6', "7:8"]
var test3 = ["20:15", "4:0", "1:3", "5:1", "9:11", "10:12", '3:6', "8:7"]
console.log(JSON.stringify(group(test1)))
console.log(JSON.stringify(group(test2)))
console.log(JSON.stringify(group(test3)))
You could use a hash table and collect all nodes in it. It works for any values.
var data = ["0:3", "1:3", "4:5", "a:8", "5:a"],
result = data
.map(function (a) { return a.split(':'); })
.reduce(function (hash) {
return function (r, a) {
if (hash[a[0]] && hash[a[1]]) {
hash[a[0]].push.apply(hash[a[0]], r.splice(r.indexOf(hash[a[1]]), 1)[0]);
hash[a[1]] = hash[a[0]];
return r;
}
if (hash[a[0]]) {
hash[a[1]] = hash[a[0]];
hash[a[1]].push(a[1]);
return r;
}
if (hash[a[1]]) {
hash[a[0]] = hash[a[1]];
hash[a[0]].push(a[0]);
return r;
}
hash[a[0]] = a.slice();
hash[a[1]] = hash[a[0]];
return r.concat([hash[a[0]]]);
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I guess, by using Object.values() and Set object you can simply do as follows in ES6.
function getConnectedVertices(a){
return [...new Set(Object.values(a.reduce((h,v) => (h[v[0]] ? h[v[1]] ? (h[v[0]] = h[v[0]].concat(h[v[1]]),
h[v[1]] = h[v[0]])
: (h[v[0]].push(v[1]),
h[v[1]] = h[v[0]])
: h[v[1]] ? (h[v[1]].push(v[0]),
h[v[0]] = h[v[1]])
: h[v[0]] = h[v[1]] = v,
h),{})))];
}
var input = ["0:3", "1:3", "4:5", "5:6", "6:8"].map(s => s.split(":")),
result = getConnectedVertices(input);
console.log(result);
with two arrays of potentially different sizes, what is best way to see if they are the same as far as it goes
for example
var a1 = [ 1, 2, 3 ];
var a2 = [ 1, 2 ];
var a3 = [ 1, 3 ];
a1 == a2 => true;
a1 == a3 => false;
am positive this has been done thousands of times and the syntax is well memorized
What about this (I'll just demonstrate on a1 and a2 -> I presume you can make function out of this):
var min_val = min(a1.length, a2.length);
var equals = true;
for(i = 0; i < min_val; i++)
{
if(a1[i] != a2[i])
{
equals = false;
break;
}
}
The result will be in equals variable of course. If you want to make function out of this, just pass a1 and a2 as arguments and return equals.
function compareArraySeq(a, b) {
return a.slice(0, b.length).join(' ') == b.slice(0, a.length).join(' ');
}
function compareArraySeq(a1, a2) {
var i, l = Math.min(a1.length, a2.length);
for (i=0; i<l; i++) {
if (a1[i] !== a2[i]) return false;
}
return true;
}
[edit] based on Tomalaks comments I'd say JSON can come to the rescue.
So, again: here's an Array extension that does what [I suppose] you want to do:
function comparePartial(arr1,arr2){
var arr2 = this, l1 = arr1.length, l2 = arr2.length;
return ( l1<1 || l2<1
? false :
JSON.stringify(arr1.slice(0, l2)) ===
JSON.stringify(arr2.slice(0, l1))
);
}
Array.prototype.comparePartial =
Array.prototype.comparePartial || comparePartial;
//usage
var a1 = [ 1, 2, 3 ]
,a2 = [ 1, 2 ]
,a3 = [ 1, 3 ]
,a4 = ['','']
,a5 = ['','','']
,a6 = []
,a7 = ['bla','doh',1]
,a8 = ['bla','doh',1,'yeah','really']
,a9 = [1,3,5,'doh']
,a10= ['1','3','5','doh']
,a11= [{a:1,b:2},{c:3,d:4}]
,a12= [{a:1,b:2},{c:3,d:4},{e:5,f:6}]
console.log(
[ a1.comparePartial(a2)
,a2.comparePartial(a1)
,a1.comparePartial(a3)
,a4.comparePartial(a5)
,a5.comparePartial(a6)
,a1.comparePartial(a6)
,a8.comparePartial(a7)
,a10.comparePartial(a9) //=> 'type safe' comparison
,a11.comparePartial(a12) //=> can compare arrays of Objects
].join(' - ')
); //=> true - true - false - true - false - false - true - false - true
function prefixEqual(a, b) {
var prefixLength = a.length < b.length ? a.length : b.length;
for(var i = 0; i < prefixLength; i+=1)
if( a[i] != b[i] )
return false;
return true;
}
Make a loop checking one spot at a time.
I have made this:
var compare = function (a1, a2) {
var l = Math.min(a1.length, a2.length);
for (var i = 0; i < l; i++) {
if (a1[i] !== a2[i]) {
return false;
}
}
return true;
}
Now you can compare arrays like this:
var a = [0, 1, 2, 3];
var b = [0, 1, 2];
var c = [0, 1, 3];
compare(a, b); //true
compare(a, c); //false
Hope this works for you :)
Fiddle link: http://jsfiddle.net/8zbJj/1/
If your arrays are strings or numbers or booleans you can compare their String values.
function compareSimpleValues(a,b){
if(a.length>=b.length)return String(a).indexOf(String(b))===0;
return String(b).indexOf(String(a))===0;
}
My application creates a JavaScript object, like the following:
myObj= {1:[Array-Data], 2:[Array-Data]}
But I need this object as an array.
array[1]:[Array-Data]
array[2]:[Array-Data]
So I tried to convert this object to an array by iterating with $.each through the object and adding the element to an array:
x=[]
$.each(myObj, function(i,n) {
x.push(n);});
Is there an better way to convert an object to an array or maybe a function?
If you are looking for a functional approach:
var obj = {1: 11, 2: 22};
var arr = Object.keys(obj).map(function (key) { return obj[key]; });
Results in:
[11, 22]
The same with an ES6 arrow function:
Object.keys(obj).map(key => obj[key])
With ES7 you will be able to use Object.values instead (more information):
var arr = Object.values(obj);
Or if you are already using Underscore/Lo-Dash:
var arr = _.values(obj)
var myObj = {
1: [1, 2, 3],
2: [4, 5, 6]
};
var array = $.map(myObj, function(value, index) {
return [value];
});
console.log(array);
Output:
[[1, 2, 3], [4, 5, 6]]
Simply do
Object.values(obj);
That's all!
I think you can use for in but checking if the property is not inerithed
myObj= {1:[Array-Data], 2:[Array-Data]}
var arr =[];
for( var i in myObj ) {
if (myObj.hasOwnProperty(i)){
arr.push(myObj[i]);
}
}
EDIT - if you want you could also keep the indexes of your object, but you have to check if they are numeric (and you get undefined values for missing indexes:
function isNumber(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
myObj= {1:[1,2], 2:[3,4]}
var arr =[];
for( var i in myObj ) {
if (myObj.hasOwnProperty(i)){
if (isNumber(i)){
arr[i] = myObj[i];
}else{
arr.push(myObj[i]);
}
}
}
If you know the maximum index in you object you can do the following:
var myObj = {
1: ['c', 'd'],
2: ['a', 'b']
},
myArr;
myObj.length = 3; //max index + 1
myArr = Array.prototype.slice.apply(myObj);
console.log(myArr); //[undefined, ['c', 'd'], ['a', 'b']]
Since ES5 Object.keys() returns an array containing the properties defined directly on an object (excluding properties defined in the prototype chain):
Object.keys(yourObject).map(function(key){ return yourObject[key] });
ES6 takes it one step further with arrow functions:
Object.keys(yourObject).map(key => yourObject[key]);
Nowadays, there is a simple way to do this : Object.values().
var myObj = {
1: [1, 2, 3],
2: [4, 5, 6]
};
console.log(Object.values(myObj));
Output:
[[1, 2, 3], [4, 5, 6]]
This doesn't required jQuery, it's been defined in ECMAScript 2017.
It's supported by every modern browser (forget IE).
The best method would be using a javascript -only function:
var myArr = Array.prototype.slice.call(myObj, 0);
x = [];
for( var i in myObj ) {
x[i] = myObj[i];
}
ECMASCRIPT 5:
Object.keys(myObj).map(function(x) { return myObj[x]; })
ECMASCRIPT 2015 or ES6:
Object.keys(myObj).map(x => myObj[x])
How about jQuery.makeArray(obj)
This is how I did it in my app.
ES8 way made easy:
The official documentation
const obj = { x: 'xxx', y: 1 };
let arr = Object.values(obj); // ['xxx', 1]
console.log(arr);
The solving is very simple
var my_obj = {1:[Array-Data], 2:[Array-Data]}
Object.keys(my_obj).map(function(property_name){
return my_obj[property_name];
});
Fiddle Demo
Extension to answer of bjornd .
var myObj = {
1: [1, [2], 3],
2: [4, 5, [6]]
}, count = 0,
i;
//count the JavaScript object length supporting IE < 9 also
for (i in myObj) {
if (myObj.hasOwnProperty(i)) {
count++;
}
}
//count = Object.keys(myObj).length;// but not support IE < 9
myObj.length = count + 1; //max index + 1
myArr = Array.prototype.slice.apply(myObj);
console.log(myArr);
Reference
Array.prototype.slice()
Function.prototype.apply()
Object.prototype.hasOwnProperty()
Object.keys()
If you want to keep the name of the object's properties as values. Example:
var fields = {
Name: { type: 'string', maxLength: 50 },
Age: { type: 'number', minValue: 0 }
}
Use Object.keys(), Array.map() and Object.assign():
var columns = Object.keys( fields ).map( p => Object.assign( fields[p], {field:p} ) )
Result:
[ { field: 'Name', type: 'string', maxLength: 50 },
{ field: 'Age', type: 'number', minValue: 0 } ]
Explanation:
Object.keys() enumerates all the properties of the source ; .map() applies the => function to each property and returns an Array ; Object.assign() merges name and value for each property.
I made a custom function:
Object.prototype.toArray=function(){
var arr=new Array();
for( var i in this ) {
if (this.hasOwnProperty(i)){
arr.push(this[i]);
}
}
return arr;
};
After some tests, here is a general object to array function convertor:
You have the object:
var obj = {
some_key_1: "some_value_1"
some_key_2: "some_value_2"
};
The function:
function ObjectToArray(o)
{
var k = Object.getOwnPropertyNames(o);
var v = Object.values(o);
var c = function(l)
{
this.k = [];
this.v = [];
this.length = l;
};
var r = new c(k.length);
for (var i = 0; i < k.length; i++)
{
r.k[i] = k[i];
r.v[i] = v[i];
}
return r;
}
Function Use:
var arr = ObjectToArray(obj);
You Get:
arr {
key: [
"some_key_1",
"some_key_2"
],
value: [
"some_value_1",
"some_value_2"
],
length: 2
}
So then you can reach all keys & values like:
for (var i = 0; i < arr.length; i++)
{
console.log(arr.key[i] + " = " + arr.value[i]);
}
Result in console:
some_key_1 = some_value_1
some_key_2 = some_value_2
Edit:
Or in prototype form:
Object.prototype.objectToArray = function()
{
if (
typeof this != 'object' ||
typeof this.length != "undefined"
) {
return false;
}
var k = Object.getOwnPropertyNames(this);
var v = Object.values(this);
var c = function(l)
{
this.k = [];
this.v = [];
this.length = l;
};
var r = new c(k.length);
for (var i = 0; i < k.length; i++)
{
r.k[i] = k[i];
r.v[i] = v[i];
}
return r;
};
And then use like:
console.log(obj.objectToArray);
You can create a simple function to do the conversion from object to array, something like this can do the job for you using pure javascript:
var objectToArray = function(obj) {
var arr = [];
if ('object' !== typeof obj || 'undefined' === typeof obj || Array.isArray(obj)) {
return obj;
} else {
Object.keys(obj).map(x=>arr.push(obj[x]));
}
return arr;
};
or this one:
var objectToArray = function(obj) {
var arr =[];
for(let o in obj) {
if (obj.hasOwnProperty(o)) {
arr.push(obj[o]);
}
}
return arr;
};
and call and use the function as below:
var obj = {1:'a', 2:'b', 3:'c', 4:'d', 5:'e'};
objectToArray(obj); // return ["a", "b", "c", "d", "e"]
Also in the future we will have something called Object.values(obj), similar to Object.keys(obj) which will return all properties for you as an array, but not supported in many browsers yet...