javascript: return every possible pairs in array - javascript

the title explains it all
somehow I'd like to use the method "Combination" that math has,
this is the Wikipedia page to be clear: https://en.wikipedia.org/wiki/Combination
I have already found the solution with two loops, I want to do it in one loop
example:
const arr = [1, 2, 3, 4]
function getPairs(arr) {
/*
desired return:
[
[1, 2], [1, 3], [1, 4],
[2, 3], [2, 4],
[3, 4]
]
*/
}

You can use Array.flatMap() to iterate the array, and Array.map() to iterate all items after the current (by slicing from index + 1), and return the pair.
const getPairs = arr => arr.flatMap((a, i) => arr.slice(i + 1).map(b => [a, b]))
const arr = [1, 2, 3, 4]
const result = getPairs(arr)
console.log(result)

You can use simple for-loops.
function getPairs(arr = []) {
if (!arr.length) return []
const pairs = []
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
pairs.push([arr[i], arr[j]])
}
}
return pairs
}
console.log(getPairs([1, 2, 3, 4]))

For a simple combination algorithm, you need to loop twice through the array.
Looking for the math expression, we see that we need to get all elements from the array (let's call this element i) and match all subsequent elements from i with it (let's call those j)
Following it, what we have is something like:
let array = [1, 2, 3, 4];
let results = [];
// Loop through the items on your array (get `i`)
for (let i = 0; i < array.length - 1; i++) {
// Loop after the current 1st loop item (get `j`) and push them to a new array
for (let j = i + 1; j < array.length; j++) {
results.push([array[i], array[j]]);
}
}
console.log(results);

Using slice and map
const arr = [1, 2, 3, 4]
console.log(arr.slice(0, -1).map((x, i) => arr.slice(i+1).map(y => [x, y])))

Related

Remove only first duplicate value and all other matching values after comparing two arrays

I have two array , I am trying to remove all matching value from 1st array which are in 2nd.
But if value is duplicate it should only remove 1st duplicate value.
For example - my two arrays are
arr1=[1,1,2,3,4,4]
arr2=[1,3,4]
it should give result as = [1,2,4]
or if my arrays are
arr1=[1,1,1,2,3,4,4,4]
arr2=[1,3,4]
it should give result as = [1,1,2,4,4]
I tried different approach using filter and includes but nothing works.
Below code removes all matching values but I want to remove all matching and only first duplicate value if it matches.
arr1 =
arr1.filter(f => !arr2.includes(f));
this.arr2.forEach(x=>{
if (this.arr1.indexOf(x)>=0)
this.arr1.splice(index,1)
})
or
this.arr1=this.arr1.filter((x,index)=>this.arr2.indexOf(x)<0 ||
this.arr1.indexOf(x)!=index )
In order to remove only the first occurrence, you can use indexOf instead. So, the solution would be:
let arr1 = [1, 1, 2, 3, 4, 4];
let arr2 = [1, 3, 4];
for (let i = 0; i < arr2.length; i++) {
if (arr1.includes(arr2[i])) {
let matchedItemIndex = arr1.indexOf(arr2[i]);
arr1[matchedItemIndex] = null;
}
}
arr1 = arr1.filter((x) => x != null);
console.log(arr1); // Expected Result: [1, 2, 4]
There are lots of ways to do this. Most of the above answers are right. But I would suggest using sets
let arr1 = [1, 1, 2, 3, 4, 4];
let arr2 = [1, 3, 4];
let result = [];
for(let i = 0; i < arr1.length; i++) {
let index = arr2.indexOf(arr1[i]);
if(index > -1) {
arr2.splice(index, 1);
} else {
result.push(arr1[i]);
}
}
console.log(result); /// [1, 2, 4]
Use Set and reduce
const process = (arr1, arr2) => {
const set2 = new Set(arr2);
return arr1.reduce((acc, curr) => {
set2.has(curr) ? set2.delete(curr) : acc.push(curr);
return acc;
}, []);
};
let arr1 = [1, 1, 2, 3, 4, 4];
let arr2 = [1, 3, 4];
console.log(process(arr1, arr2));
arr1=[1,1,1,2,3,4,4,4]
arr2=[1,3,4]
console.log(process(arr1, arr2));

Find count of matched elements in two arrays?

So I want to create a function in js which takes two arrays and compare them and give a score depending on how many spots in the two arrays match. Is it right or it's bd written. I am new on coding.
Another problem I have is when I try to execute it on chrome's console. It says that compare is not defined
let score = 0;
function compare(arr1, arr2) {
for (let i = 0; i < arr2.length; i++) {
for (let j = 0; j < arr1.length; j++) {
if(arr1[j] === arr2[i]){
score++;
}
}
}
You can use .reduce() to find count of matched elements:
let arr1 = [1, 2, 3, 4, 5],
arr2 = [3, 4, 5, 6, 7],
compare = (a1, a2) => arr1.reduce((a, c) => a + arr2.includes(c), 0);
console.log(compare(arr1, arr2));
Alternatively, you can use .filter() to find array of matched elements and use its length to determine the count.
let arr1 = [1, 2, 3, 4, 5],
arr2 = [3, 4, 5, 6, 7],
compare = (a1, a2) => arr1.filter(v => arr2.includes(v)).length;
console.log(compare(arr1, arr2));
Docs:
Array.prototype.reduce()
Array.prototype.includes()
Array.prototype.filter()
Arrow Functions
This should work for you:
Updated the code as required by you :
let arr1 = [1, 2, 3, 4];
let arr2 = [3,2,3,4,5];
function compare(arr1,arr2){
let count=0;
const max=arr1.length>arr2.length ? arr2.length : arr1.length;
for(var i=0;i<max;i++){
if(arr1[i]==arr2[i]){
count++;
}
}
return count;
}
console.log(compare(arr1,arr2));

How to find the greatest number of times each element occurs in a nested array?

How to find the greatest number of times each element occurs in a nested array?
I am looking to find the greatest number of times each element occurs in any of the subarrays. I am NOT looking for the element that occurs the most times in the entire nested array.
Let's say my nested array is [[2, 3, 5], [3, 3, 5], [2, 2, 3, 5]].
The number 2 appears two times in one of the subarrays. The number 3 appears two times in one of the subarrays. The number 5 appears one time in one of the subarrays.
The end result I am looking for is [2, 2, 3, 3, 5].
What is the best way to do this? Below is my approach, which is not very good.
function makeNewArray(arr) {
// add the # to the numbers that appear once and add the ## to the numbers that appear twice
for (var j = 0; j < arr.length; j++) {
for (var i = 0; i < arr[j].length; i++) {
if (arr[j][i] === arr[j][i+1]) {
arr[j][i] = arr[j][i] + '#';
arr[j][i+1] = arr[j][i+1] + '#';
} else {
arr[j][i] = arr[j][i] + '#';
}
}
}
// flatten the array
arr = arr.reduce(function(a, b) { return a.concat(b); });
// remove the duplicates from the array
arr = arr.filter(function(a, b) { return arr.indexOf(a) == b; });
// remove the ## and # from the array
for (var i = 0; i < arr.length; i++) {
arr[i] = parseInt(arr[i]);
}
return arr;
}
makeNewArray([[2, 3, 5], [3, 3, 5], [2, 2, 3, 5]]);
Just based on your question and not the result you expect that I don't really get, here is a working solution that will find the highest number of occurrence.
var a = [
[2, 3, 5],
[3, 3, 5],
[2, 2, 3, 5]
];
var o = {};
var max = 0;
var highest = null;
for (var i = 0; i < a.length; i++) {
for (var j = 0; j < a[i].length; j++) {
if (!o.hasOwnProperty(a[i][j])) {
o[a[i][j]] = 1;
} else {
o[a[i][j]]++;
}
if (o[a[i][j]] > max) {
max = o[a[i][j]];
highest = a[i][j];
}
}
}
//this is the number with the highest occurence
console.log(highest);
This ES6 solution iterates the sub arrays, and creates a map of the values, then in it moves the highest values to a map of the entire array. Afterwards, we map the Map entries (no pan intended) to new arrays that are filled with the numbers according to their highest count, and flatten the result.
var data = [[2, 3, 5], [3, 3, 5], [2, 2, 3, 5]];
var result = [].concat(... // flatten the end result
[... // convert the Map to entries array
data.reduce((r, s) => { // reduce the array into a map of counts
s.reduce((map, num) => map.set(num, (map.get(num) || 0) + 1), new Map) // get a Map of the current sub array counts
.forEach((v, k) => r.set(k, Math.max(r.get(k) || 0, v))); // update the global Map if the sub array count of a number is higher
return r;
}, new Map)]
.map((s) => Array.from({ length: s[1] }, () => s[0]))); // map the entries into new sub arrays
console.log(result);

Move every other value from array into a new array

I have two one-dimensional arrays, a and b. a has values and b is empty. The length of a is an even number. I'd like to remove every other value from a and move them to b, in the same order as they were placed in a.
var a = [1, 2, 3, 4, 5, 6], b = [];
becomes
var a = [1, 3, 5], b = [2, 4, 6];
I figured that filter would do the trick but I'm not that happy with the performance of it since the average length of a is 300-400.
b = a.filter((i, idx) => {
return idx % 2 == 0;
});
a = a.filter((i, idx) => {
return idx % 2 == 1;
});
I've also been looking at lodash to see if that library had anything that might help me and the only function that's near what I'm looking for is _.chunk(array, \[size=1\]).
I appreciate any and all help to help me figure out a better, faster way to do this.
Since you mentioned lodash you could do this with _.partition:
let a = [1, 2, 3, 4, 5, 6];
let b = [];
let i = -1;
[a, b] = _.partition(a, (item) => i++ % 2);
console.log(a);
console.log(b);
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
Partition's predicate is the identity function, which doesn't include the index of the item, so this comes with a compromise of an external index i.
Of course, you could always wrap this functionality into it's own function:
const splitEvenOdd = (array, i = -1) => _.partition(array, (item) => i++ % 2);
let a = [1, 2, 3, 4, 5, 6];
let b = [];
[a, b] = splitEvenOdd(a);
console.log(a);
console.log(b);
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
Vanilla JS ES5, simple and clean.
var a = [1, 2, 3, 4, 5, 6], b = [];
for(var i = a.length-1; i >= 0; i--) {
if(i % 2 === 1) {
b.unshift(a.splice(i, 1)[0])
}
}
Basically, it is iterating through a backwards, and if the condition is true splicing the item und adding it as first item of b.
To loop through the source once, the values can be added to a specific array depending on the index. For example:
const source = [1, 2, 3, 4, 5, 6];
let arrs = [[],[]];
for(let i = 0; i< source.length; i++)
arrs[i%2].push(source[i]);
let [a,b] = arrs;
console.log(a);
console.log(b);
Alternatively, if it's important to alter the original arrays, a can be filled in a direct iteration, since the index being processed is always ahead of the one being filled:
let a = [1, 2, 3, 4, 5, 6], b= [];
for(let i = 0; i< a.length; i++)
(i % 2 ? b : a)[Math.floor(i/2)] = a[i];
a.splice(a.length/2);
console.log(a);
console.log(b);
The best performance you can get for this is 0(n) or linear time since you have to iterate through the entire array. What may help is reducing the number of loops
var a=[];
var b=[];
function splitArray(arr)
{
for (var i=0;i<arr.length;++i)
{
if (arr[i]%2 == 0)
b.push(arr[i]);
else
a.push(arr[i]);
}
}
What this does is reduces the number of times you have to iterate through the original array from 2 to 1

JavaScript: Swapping array values by index

I'm trying to animate the sorting of a few elements with jQuery and my sorting map is defined like this:
var mapping = [
[0, 5],
[1, 4],
[2, 3],
[3, 2],
[4, 1],
[5, 0]
];
mapping[0][0] is the element's index and mapping[0][1] is the target index.
My solution was basically this:
var elements = [1, 2, 3, 4, 5, 6];
for (var i = 0; i < elements.length; i++) {
var clone1 = elements[mapping[i][0]];
var clone2 = elements[mapping[i][1]];
elements[mapping[i][0]] = clone2;
elements[mapping[i][1]] = clone1;
}
console.log(elements);
The problem is, I am working on the object I'm modifying and the operations undo themselves; instead of reversing the array, I get the same array back.
How would I swap elements like this in JavaScript? Here's a JSFiddle example of the code.
// [source, target]
var mapping = [
[0, 5],
[1, 4],
[2, 3],
[3, 2],
[4, 1],
[5, 0]
];
var elements = [1, 2, 3, 4, 5, 6];
function swapElements(elements, mapping) {
var tmp = new Array(elements.length);
for(var i = 0, l = mapping.length; i < l; i++) {
tmp[mapping[i][1]] = elements[mapping[i][0]];
}
for(var i = 0, l = elements.length; i < l; i++) {
elements[i] = tmp[i];
}
}
swapElements(elements, mapping);
console.log(elements);​
Some functional fun with accessor function
var at = function(arr) { return function(i) { return arr[i] } };
[5,4,3,2,0,1].map( at(['a','b','c','d','e','f']) )
this will returns ['f','e','d','c','a','b']
You swap elements twice from 0 to 5 and from 5 to 0 again :) Try
for (var i = 0; i < elements.length / 2; i++)
and it will be ok.
Look here
You're changing the array during a loop of it. And it's swapped twice for each pair, so the result is the same. You may need another arr to store mapped value:
var result = [];
for(var i = 0; i<mapping.length; i++){
result[mapping[i][0]] = elements[mapping[i][1]];
}
console.log(result);
Just define a temporary array:
var elements = [1, 2, 3, 4, 5, 6];
var temp = [];
for (var i = 0; i < elements.length; i++) {
temp.push(elements[mapping[i][1]]);
}
elements = temp;
Just_Mad's answer is correct if you are only trying to reverse the list. But if you want to be able to handle any mapping configuration you will need a different approach.
If you don't care about memory space you could just iterate through the mapping list and copy the element at index "mapping[i][0]" to a new array at index "mapping [i][1]". Then just return the new array. This should handle whatever mapping you put into the system (you just have to decide if and how you want to handle mappings that leave empty spaces and/or override spaces)

Categories