Compare array objects to equality - javascript

I am searching for a function which compare how much values match in an array. It should be sequence dependent. That mean i.e. the first object in the first array should be compared to equality to the first object in the second array and so on. I actually looked at this, but there become only the length compared and the length is in my case always the same. The possibly objects in the array are 1,2,3,4,5,6,7,8,9. Should I split the arrays and compare them then and when yes how?
Here are two examples:
var array1 = ["3","4","2"];
var array2 = ["9","4","7"];
// result = 1
second example:
var array1 = ["9","4","7","3"];
var array2 = ["3","4","7","2"];
// result = 2

Try this
var array1 = ["3","4","2"];
var array2 = ["9","4","7"];
function equal(array1, array2) {
var len = array1.length, i, count = 0;
for (i = 0; i < len; i++) {
if (array1[i] === array2[i]) {
count++;
}
}
return count;
}
console.log(equal(array1, array2));

Solution which iterates over the items and count the equal elements.
function compare(a1, a2) {
var i = 0, count = 0;
while (i < a1.length && i < a2.length) {
a1[i] === a2[i] && count++;
i++;
}
return count;
}
document.write(compare(["3", "4", "2"], ["9", "4", "7"]) + '<br>');
document.write(compare(["9", "4", "7", "3"], ["3", "4", "7", "2"]) + '<br>');

Related

Combine each element of an array with the ones after it

I am trying to combine items in an array, with every item below it. It should make a set of the current character and each character below it, and iteratively walk down the array. For example, if I have an array like this:
var myArray = ['A','B','C','D']
I would like an output like this:
AB AC AD BC BD CD
The code I have is getting me close, but I am having a hard time figuring out the rest. Here is what I have so far:
var myArray = ['A', 'B', 'C', 'D']
var sql_parts = []
var string = "";
for (var i = 0; i < myArray.length; i++) {
recurse_function(string, i)
}
console.log(sql_parts)
function recurse_function(string_val, count) {
if ((myArray.length - count) == 0) {
return string_val;
} else {
string_val += myArray[count]
sql_parts.push(string_val)
recurse_function(string_val, count + 1)
}
}
But this produces:
["A", "AB", "ABC", "ABCD", "B", "BC", "BCD", "C", "CD", "D"]
Here is one solution:
Define the recursive function to take the array and an empty list initially to store the combinations
The base condition is when the array is empty or has one element
Otherwise, Remove the first element "start"
Iterate over the array to store its combinations with its following elements
Recur again with array and combinations updated
function recurse_function(array, combinations = []) {
if(array.length <= 1) return combinations;
const start = array.shift();
for(let i = 0; i < array.length; i++) combinations.push(`${start}${array[i]}`);
return recurse_function(array, combinations);
}
console.log( recurse_function(['A','B','C','D']) );
var myArray = ['A','B','C','D']
var sql_parts = []
for(var i =0; i< myArray.length; i++){
var a = myArray[i]
for(var j = i+1; j<myArray.length; j++){
var b=myArray[j]
var c= a+b
sql_parts.push(c)
}
}
I think this is something that you're looking for, it's a function that is very cheap on resources. Its not recursive (why you now would need something like that for this simple scenario)
var myArray = ['A','B','C','D']
let [a, b, iter] = [0, 1, 2]
let result = []
for (;a < myArray.length; a++) {
for (;b < myArray.length; b++) {
result.push(myArray[a]+myArray[b])
}
b = iter++
}
console.log(result)
I don't think you need to recurse in this particular case. You can simply combine the current element with the following ones with flatMap:
['A','B','C','D'].flatMap((x, i, xs) => xs.slice(i+1).map(y => x+y));
//=> ["AB", "AC", "AD", "BC", "BD", "CD"]
var myArray = ['A', 'B', 'C', 'D'];
var result = [];
myArray.forEach((item, index) => {
myArray.forEach((item2, index2) => (index < index2 ? result.push(item + item2) : ''));
});
console.log(result);

Create a string of specified copies of a given string

I am trying to iterate over the original string 3 times. The result I get is:
["a","b","c","d",undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined]
The correct result should be: ["a", "b", "c", "d", "a", "b", "c", "d", "a", "b", "c", "d"]
function makeCopies (str, howmany) {
let newCopy = [];
for(let i = 0; i < str.length * howmany; i++) {
newCopy.push(str[i])
}
return newCopy;
}
console.log(makeCopies("abcd", 3))
I have tried many variations but nothing works, this is the closest I got.
JavaScript has a repeat Method on Strings. You can just use "abcd".repeat(3) and you will get "abcdabcdabcd". If you really want an array of the chars, you can spread the string into an array with [..."abcd".repeat(3)].
Javascript has a nice utility for this String.prototype.repeat. You can then split it on every character if an array is what you want.
console.log("abcd".repeat(3).split(""))
The length of the array is becoming 12 when you multiply str.length * howmany, and when it gets further than the fourth value it can't find anything and so becomes undefined.
A solution is you can wrap the main loop in another loop which will run howmany times.
function makeCopies (str, howmany) {
let newCopy = [];
for (let i = 0; i < howmany; i++) {
for(let j = 0; j < str.length; j++) {
newCopy.push(str[j])
}
}
return newCopy;
}
console.log(makeCopies("abcd", 3))
const makeCopies = (string, count) => new Array(count).join(string).split('');
console.log(makeCopies('abcd', 4))
Why don’t you use repeat() ?
const res = "abc".repeat(3); // abcabcabc
If you need it as array, you can:
res.split(""); // ["a", "b", "c", ...]
You are iterating outside the bounds of original string
str[i]; // i < str.length * howmany;
Try create two cycles instead:
for(let i = 0; i < howmany; i++) {
for(let j = 0; j < str.length; j++) {
newCopy.push(str[j])
}
}

Breaking strings in an array into subarrays

Doing the DNA challenge and so close but clearly misunderstanding prototype.split(""). What's the best way to turn these strings ["AC", "CA", "TA"] into subarrays? [["A","C"]["C","A"]["T","A"]]
function pairElement(str) {
//break into array
var arr = str.split("");
//add new letter (could be refactored as switch)
for (i = 0; i < arr.length; i++) {
if (arr[i] == "G") {
arr[i] += "C";
} else if (arr[i] == "C") {
arr[i] += "G";
} else if (arr[i] == "T") {
arr[i] += "A";
} else if (arr[i] == "A") {
arr[i] += "T";
}
}
//break into arrays again
//this is how I'm trying to use.split to break it up. Doesn't work.
var broken = [];
for (x = 0; x < arr.length; x++) {
broken += arr[x].split("");
}
//return
return arr;
}
console.log(pairElement("GCG"));
you can use .map and split them by ""
var o = ["AC", "CA", "TA"];
var s = o.map(e=> e.split(""));
console.log(s)
You actually have to just push the split result in the broken array and return it !
function pairElement(str) {
//break into array
var arr = str.split("");
//add new letter (could be refactored as switch)
for (i = 0; i < arr.length; i++) {
if (arr[i] == "G") {
arr[i] += "C";
} else if (arr[i] == "C") {
arr[i] += "G";
} else if (arr[i] == "T") {
arr[i] += "A";
} else if (arr[i] == "A") {
arr[i] += "T";
}
}
//break into arrays again
//this is how I'm trying to use.split to break it up. Doesn't work.
var broken = [];
for (x = 0; x < arr.length; x++) {
broken.push(arr[x].split(""));
}
//return
return broken;
}
console.log(pairElement("GCG"));
To answer your 'what's the best way' question, map your arrays into the split versions of themselves:
const subarrays = array.map(pair => pair.split());
Very simple in functional style:
> seq = ['AC', 'CA', 'TA']
[ 'AC', 'CA', 'TA' ]
> seq.map(s => s.split(''))
[ [ 'A', 'C' ], [ 'C', 'A' ], [ 'T', 'A' ] ]
Overall, I'd do some refactoring on the whole function:
var m = new Map([["G", "C"], ["C", "G"], ["A", "T"], ["T", "A"]]);
function pairElement(str) {
return [...str].map(c => [c, m.get(c)]);
}
console.log(pairElement("GCG"));
And if there's a guarantee that the sub-arrays are never mutated, then you can save a good bit of memory by reusing arrays instead of creating them over and over.
var m = new Map([["G", ["G", "C"]], ["C", ["C", "G"]], ["A", ["A", "T"]], ["T", ["T", "A"]]]);
function pairElement(str) {
return [...str].map(c => m.get(c));
}
console.log(pairElement("GCG"));
But to directly answer your question, you can do it without explicit .split() calls. Since you know there's always two characters, you can use parameter destructuring on the strings.
var arr = ["AC", "CA", "TA"];
var s = arr.map(([a, b]) => [a, b]);
console.log(s)
Or even a little shorter using rest syntax, like this:
var arr = ["AC", "CA", "TA"];
var s = arr.map(([...a]) => a);
console.log(s)
Or using spread syntax in an array literal:
var arr = ["AC", "CA", "TA"];
var s = arr.map(s => [...s]);
console.log(s)

Efficient algorithm to get the combinations of all items in object

Given an array or object with n keys, I need to find all combinations with length x.
Given X is variable. binomial_coefficient(n,x).
Currently I'm using this:
function combine(items) {
var result = [];
var f = function(prefix, items) {
for (var i = 0; i < items.length; i++) {
result.push(prefix + items[i]);
f(prefix + items[i], items.slice(i + 1));
}
}
f('', items);
return result;
}
var combinations = combine(["a", "b", "c", "d"]);
The output is:
["a", "ab", "abc", "abcd", "abd", "ac", "acd", "ad", "b", "bc", "bcd", "bd", "c", "cd", "d"]
So if I want the binomial coefficient x=3 from n=4 I select all the strings with length equal to three. {abc, abd, acd, bcd}.
So I do this in two steps.
Is there a more efficient algorithm with smaller complexity?
Link: Solution performance (JSPerf)
Your algorithm is almost O(2^n), you can discard a lot of combinations, but the num of elements will be (n! * (n-x)!) / x!.
To discard the useless combinations you can use an indexed array.
function combine(items, numSubItems) {
var result = [];
var indexes = new Array(numSubItems);
for (var i = 0 ; i < numSubItems; i++) {
indexes[i] = i;
}
while (indexes[0] < (items.length - numSubItems + 1)) {
var v = [];
for (var i = 0 ; i < numSubItems; i++) {
v.push(items[indexes[i]]);
}
result.push(v);
indexes[numSubItems - 1]++;
var l = numSubItems - 1; // reference always is the last position at beginning
while ( (indexes[numSubItems - 1] >= items.length) && (indexes[0] < items.length - numSubItems + 1)) {
l--; // the last position is reached
indexes[l]++;
for (var i = l +1 ; i < numSubItems; i++) {
indexes[i] = indexes[l] + (i - l);
}
}
}
return result;
}
var combinations = combine(["a", "b", "c", "d"], 3);
console.log(JSON.stringify(combinations));
For example, the first combination have the indexes: [0, 1, 2] and the elements ["a", "b", "c"]. To compute the next combination, It get the last index 2 and try to increment, if the increment is lower than the max position (in this case 4), the next combination is reached, but if It is not, It must increment to a previous index.
You could use an iterative and recursive approach with stress on the length of the array and the still needed items.
Basically combine() takes an array with the values to combine and a size of the wanted combination results sets.
The inner function c() takes an array of previously made combinations and a start value as index of the original array for combination. The return is an array with all made combinations.
The first call is allways c([], 0), because of an empty result array and a start index of 0.
function combine(array, size) {
function c(part, start) {
var result = [], i, l, p;
for (i = start, l = array.length; i < l; i++) {
p = part.slice(0); // get a copy of part
p.push(array[i]); // add the iterated element to p
if (p.length < size) { // test if recursion can go on
result = result.concat(c(p, i + 1)); // call c again & concat rresult
} else {
result.push(p); // push p to result, stop recursion
}
}
return result;
}
return c([], 0);
}
console.log(combine(["a", "b", "c", "d"], 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }
We could create just those combinations we are interested in. Also, rather than cloning arrays by using slice in each call, we can use a pointer to the original array. Here's one version. Converting it to recursion without an external global variable is left as an exercise.
function choose(ns,r){
var res = [];
function _choose(i,_res){
if (_res.length == r){
res.push(_res);
return;
} else if (_res.length + ns.length - i == r){
_res = _res.concat(ns.slice(i));
res.push(_res);
return
}
var temp = _res.slice();
temp.push(ns[i]);
_choose(i + 1,temp);
_choose(i + 1,_res);
}
_choose(0,[]);
return res;
}
var combinations = choose(["a", "b", "c", "d"], 3);
console.log(JSON.stringify(combinations));
And here's the true recursion.
function seq(a,b){
var res = [];
for (var i=a; i<=b; i++)
res.push(i);
return res;
}
function f(n,k){
if (k === 0)
return [[]];
if (n === k)
return [seq(1,n)];
let left = f(n - 1, k - 1),
right = f(n - 1, k);
for (let i=0; i<left.length; i++)
left[i].push(n);
return left.concat(right);
}
console.log(JSON.stringify(f(4,3)))

Compare elements of two arrays

I have two javascript array and I need to compare them. For example, suppose I have these two arrays:
var array1 = ["1", "2", "3", "4"];
var array2 = ["4", "1", "3", "2"];
These arrays are equal in fact and I want to get true as a result of comparison. What is the best and fastest way for doing that?
What you really have are two sets, not arrays, but unfortunately JavaScript does not provide any sort of "set" datatype. The easiest way to do this type of check is by using some sort of functional JavaScript library, such as lodash.
Using lodash's _.union function makes this trivially easy.
function setsEqual(a, b) {
var u = _.union(a, b);
return u.length === a.length && u.length === b.length;
}
If you want to do this without external libraries, you can do so using Array.prototype.every.
function setsEqual(a, b) {
return a.length === b.length
&& a.every(function (v) { return b.indexOf(v) !== -1; });
}
The best way and fastest way to do this is using object which keep tracks the value of and its count. Then we can see if it exist in second array. Try this
function compare(arr1, arr2){
var obj={}, len = arr1.length, i=0, isSame=true, prop;
if(arr1.length === arr2.length){
for(;i<len;i++){
if(obj[arr1[i]]){
obj[arr1[i]] = obj[arr1[i]]+1;
} else{
obj[arr1[i]] =1;
}
}
i=0, len = arr2.length;
for(;i<len;i++){
if(obj[arr2[i]]){
obj[arr2[i]] = obj[arr2[i]]-1;
} else{
isSame = false;
break;
}
}
for (prop in obj){
if(obj[prop] > 0){
isSame = false;
break;
}
}
}else{
isSame = false;
}
return isSame;
}
Try removing matching elements until both elements are empty:
var array1 = ["1", "2", "3", "4", "1", "5"];
var array2 = ["1", "5", "2", "3", "4", "1"];
var isSame = false;
if(array1.length != array2.length)
isSame = false;
else
{
for(var i = 0; i < array1.length; i ++)
{
var removed = false;
for(var j = 0; j < array2.length; j ++)
{
if(array2[j] == array1[i])
{
// remove from array2
array1.splice(i, 1);
// remove from array1
array2.splice(j, 1);
// go back 1 for i
removed = true;
i --;
break;
}
}
if(!removed)
break;
}
if(array1.length == 0 && array2.length == 0)
isSame = true;
}
I don't suppose that is a fastest approach but it can be useful for a little arrays with primitives
function compareArrays(a, b) {
var copyA = a.slice(),
copyB = b.slice();
if (a.length !== b.length) { return false; }
return copyA.sort().toString() === copyB.sort().toString();
}
Return status from function after comparing two array.
arr1 = [101,12,13,10,4];
arr2 = [101,4,12,13,10];
function compareTwoArray(arr1, arr2) {
return arr1.length === arr2.length &&
arr1.sort().every((val, index)=> val === arr2.sort()[index]);
}
console.log(compareTwoArray(arr1, arr2))

Categories

Resources