Consider the following scenario;
var defaultArr = ['a', 'b', 'c', 'd'];
var availArr = [];
var selectedArr = [];
If I am passing array some index's value in param's, I need to split up my array's
Example:
If Array Index : 0,2
Expected result:
availArr = ['b', 'd'];
selectedArr = ['a', 'c'];
Is there any default method to achieve this?
Failrly easy with Array.reduce
var defaultArr = ['a', 'b', 'c', 'd'];
var indexes = [0,2];
var result = defaultArr.reduce(function(p, c, i){
if(indexes.indexOf(i)>-1)
p.selectedArr.push(c);
else
p.availArr.push(c);
return p;
}, {availArr: [], selectedArr:[]});;
console.log('availArr',result.availArr);
console.log('selectedArr',result.selectedArr);
This works because reduce takes a callback argument which is passed 3 arguments - in my example above
p the seed object passed in
c the current array element
i the index of the current element
And uses that information along with indexOf to determine which result array to push to.
You could use Array#reduceRight and iterate the indices array.
var defaultArr = ['a', 'b', 'c', 'd'],
availArr = defaultArr.slice(),
selectedArr = [],
indices = [0, 2];
indices.reduceRight(function (_, a) {
selectedArr.unshift(availArr.splice(a, 1)[0]);
}, 0);
console.log(availArr);
console.log(selectedArr);
var defaultArr = ['a', 'b', 'c', 'd'];
var availArr = [];
var selectedArr = [];
function splitArray(indexes) {
availArr = defaultArr;
indexes.forEach(function(idx) {
let item = availArr.splice(idx, 1)[0];
selectedArr.push(item);
})
}
splitArray([0, 2]);
console.log(availArr);
console.log(selectedArr);
You can use Array methods like forEach and includes
var given = ['a', 'b', 'c', 'd'];
var indexes = [0, 2];
var available = [];
var selected = [];
given.forEach(function (v, i) {
if (indexes.includes(i)) {
selected.push(v);
} else {
available.push(v);
}
});
document.write(JSON.stringify({
given: given,
available: available,
selected: selected
}));
In JS Array.prototype.reduceRight() is the ideal functor to iterate over an array and to morph it by removing items. Accordingly i would approach this job as follows;
var defaultArr = ['a', 'b', 'c', 'd'],
indices = [0, 2];
result = defaultArr.reduceRight((p,c,i,a) => indices.includes(i) ? p.concat(a.splice(i,1)) : p ,[]);
console.log(defaultArr,result);
You can use array.splice + array.concat to achieve this
var defaultArr = ['a', 'b', 'c', 'd'];
var availArr = [];
var selectedArr = [];
function parseIndexes(indexArr){
var deleteCount = 0;
availArr = defaultArr.map(x=>x);
indexArr.forEach(function(i){
selectedArr = selectedArr.concat(availArr.splice(i-deleteCount,1))
deleteCount++;
});
console.log(availArr, selectedArr)
}
parseIndexes([0,2])
With only Array.filter
var array = ['a', 'b', 'c', 'd'];
var indexes = [0, 2]
array.filter(function(el, i) {
return indexes.indexOf(i) !== -1
});
// ["a", "c"]
With array the array of your elements, objects, strings... and indexes the array containing all the indexes of the elements you want to keep, you just remove from the arrayarray all the elements whose id isn't in theindexes array.
The array of all selected entries can be obtained in one line via the Array.map:
var defaultArr = ['a', 'b', 'c', 'd']
var index = [0,2]
var selectedArr = index.map(i => defaultArr[i]) //=> ['a', 'c']
Then the array of the remaining entries can be retrieved e.g. with the Ramda's difference operator:
var availArr = R.difference(defaultArr, selectedArr) //=> ['b', 'd']
Related
Given this input:
[
['a', 'b', 'c']
['b', 'c', 'd']
['a', 'd', 'b']
]
I'd like to return this output:
[
['a', 'b', 'c']
[null, 'b', 'c', 'd']
['a', 'b', null, 'd']
]
Such that each matching string in each array is in the same position in the array, and any gaps are null values.
Context
I need to render a bunch of arbitrary strings like above, but ensure that each common string between the columns are rendered on the same horizontal line. In this example, each array is a column in the above image. Once I have the underlying array set up correctly, I can just use simple loops to render the strings in the correct position.
You could use reduce() method and one ES6 Set to keep current values.
const input = [['a', 'b', 'c'],['b', 'c', 'd'],['a', 'd', 'b']]
const all = new Set
const result = input.reduce((r, arr) => {
arr.forEach(e => all.add(e))
r.push([...all].sort().map(e => arr.includes(e) ? e : null))
return r;
}, []);
console.log(result)
This version includes a null at any place it might be applicable, including at the end of the first row.
const transform = (orig) => {
const template = Array.from(new Set(orig.reduce((a, b) => a.concat(b))))
return orig.map(row => row.slice(0).reduce( // `slice` to avoid mutating original
(output, val) => {
const idx = template.indexOf(val)
output[idx] = val
return output
} , Array(template.length).fill(null)
))
}
const orig = [['a', 'b', 'c'], ['b', 'c', 'd'], ['a', 'd', 'b']]
console.log(transform(orig))
If you want your values sorted, you could just add a sort invocation at the end of the first line:
const template = Array.from(new Set(orig.reduce((a, b) => a.concat(b)))).sort()
As it is, they are sorted by when the values are first seen.
The template is just the result of taking the unique values from the concatenation of all the rows, in this case, ['a', 'b', 'c', 'd'], and it serves to tell the remainder of the code where in each row to place the given value.
You could always map over the rows again to remove any trailing nulls, but if they're not a problem, I don't think it would be worth it.
for(let i = 0; i < table[0].length; i++) {
const match = table[0][i];
for(const row of table.slice(1)) {
if(row[i] !== match) {
row.splice(i, 0, null);
}
}
}
Create an 'intermediate' array that contains all the possible values, and from there the path is quite simple:
var Array = [['a', 'b', 'c'], ['b', 'c', 'd'], ['a', 'd', 'b']];
var TempArray = [];
var EndArray = [];
Array.forEach(function(a) {
a.sort();
a.forEach(function(b) {
if (!TempArray.includes(b)) {
TempArray.push(b);
}
});
});
TempArray.sort();
Array.forEach(function(a) {
a.sort();
var Member = [];
TempArray.forEach(function(b) {
Member.push((a.includes(b)) ? b : null);
});
EndArray.push(Member);
});
console.log(EndArray);
I have 2 arrays. I am trying to return the similar values between the 2 but in the order of the second. For example, take a look at the two arrays:
array1 = ['a', 'b', 'c']
array2 = ['b', 'c', 'a', 'd']
What I would like to return is this:
sim = ['b', 'c', 'a']
Here is a link to what I am trying to accomplish. Currently the script is faulty and not catching the corner case.
You could use a Set for array1 use Array#filter array2 by checking the set.
var array1 = ['a', 'b', 'c'],
array2 = ['b', 'c', 'a', 'd'],
theSet = new Set(array1),
result = array2.filter(v => theSet.has(v));
console.log(result);
Some annotations to your code:
function arr_sim (a1, a2) {
var //a = {}, // take an object as hash table, better
a = Object.create(null), // a really empty object without prototypes
sim = [],
i; // use single declaration at top
for (i = 0; i < a1.length; i++) { // iterate all item of array 1
a[a1[i]] = true;
}
for (var i = 0; i < a2.length; i++) {
if (a[a2[i]]) {
sim.push(a2[i]); // just push the value
}
}
return sim;
}
console.log(arr_sim(['a', 'b', 'c'], ['b', 'c', 'a', 'd']));
You can iterate array2 with a filter, and check if the value is contained in array1:
let array1 = ['a', 'b', 'c'];
let array2 = ['b', 'c', 'a', 'd'];
let sim = array2.filter((entry) => {
return array1.includes(entry);
});
console.log(sim);
I think this is what you are looking for?
function arr_sim (a1, a2) {
a1 = Array.isArray(a1)?a1:typeof a1 == "string"?a1.split(""):false;
a2 = Array.isArray(a2)?a1:typeof a2 == "string"?a2.split(""):false;
if(!a1 || !a2){
alert("Not valid values");
return;
}
var filterArray = a1.filter(function(val){
return a2.indexOf(val) !== -1;
})
return filterArray;
}
console.log(arr_sim(['a', 'b'], ['b', 'a', 'c', 'd']));
console.log(arr_sim("abcd", "abcde"));
console.log(arr_sim("cxz", "zcx"));
Try this
const arr_sim = (a1, a2) => a2.filter(a => a1.includes(a))
console.log(arr_sim(['a', 'b', 'c'], ['b', 'c', 'a', 'd']));
try this example here similar-values betwe
en two arrays
var a1 = ['a' ,'b'];
var a2 = ['a' ,'b' ,'c'];
var result = arr_sim(a1,a2);// call method arr_sim
console.log(result);
function arr_sim (a1, a2) {
var similar = [];
for( var i = 0 ; i <a1.length ; i++ ){ // loop a1 array
for( var j = 0 ; j <a2.length ; j++ ){ // loop a2 array
if( a1[i] == a2[j] ){ // check if is similar
similar.push(a1[i]); // add to similar array
break; // break second loop find that is similar
} // end if
} // end second lopp
} // end first loop
return similar; // return result
} // end function
In my javascript code, I have the following two arrays,
var arr1 = ['a', 'b', 'c'];
var arr2 = ['c', 'd'];
I want to know if any of the element of arr2 present in arr1. In the above case, it is present.
Yes, it can be easily found by iterating over. But I am looking for a simpler way. If there are any lodash function, that will also be useful. Thanks in advance
You can easily check it with Array.prototype.every method combined with Array.prototype.indexOf:
var arr1 = ['a', 'b', 'c'];
var arr2 = ['c', 'd'];
console.log( arr2.every(el => arr1.indexOf(el) > -1) )
UPD. Correction: I read the question as "if every of the elements" for which above answer will do. In case of "if any of the elements" you need to use Array.prototype.some instead of every:
var arr1 = ['a', 'b', 'c'];
var arr2 = ['c', 'd'];
console.log( arr2.some(el => arr1.indexOf(el) > -1) )
You can use some that will return true/false and intersection that will find same elements in both arrays.
var arr1 = ['a', 'b', 'c'];
var arr2 = ['c', 'd'];
var result = _.some(_.intersection(arr1, arr2))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
With plain js you can also just use some and includes
var arr1 = ['a', 'b', 'c'];
var arr2 = ['c', 'd'];
var result = arr1.some(e => arr2.includes(e))
console.log(result)
You can use _.intersection from docs here
intersection returns you the elements both array has
var d = _.intersection(arr1, arr2);
Here is the fiddle https://jsfiddle.net/W4QfJ/3897/
You can get the common elements on intersection variable.
var intersection = $.grep(arr1 , function(element) {
return $.inArray(element, arr2) !== -1;
});
console.log(intersection);
I have an Array with duplicate values.
I want to create a Set to get the distinct values of that array and remove or create a new Array that will have the same data MINUS the elements required to create the Set.
This is not just a matter of remove the duplicates, but remove a SINGLE entry of a each distinct value in the original array
Something like that works, but I wonder if there is a more direct approach:
let originalValues = [
'a',
'a',
'a',
'b',
'b',
'c',
'c',
'd'
];
let distinct = new Set(originalValues);
/*
distinct -> { 'a', 'b', 'c', 'd' }
*/
// Perhaps originalValues.extract(distinct) ??
for (let val of distinct.values()) {
const index = originalValues.indexOf(val);
originalValues.splice(index, 1);
}
/*
originalValues -> [
'a',
'a',
'b',
'c'
];
*/
Use Array#filter in combination with the Set:
const originalValues = ['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd'];
const remainingValues = originalValues.filter(function(val) {
if (this.has(val)) { // if the Set has the value
this.delete(val); // remove it from the Set
return false; // filter it out
}
return true;
}, new Set(originalValues));
console.log(remainingValues);
You could use closure over a Set and check for existence.
let originalValues = ['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd'],
result = originalValues.filter((s => a => s.has(a) || !s.add(a))(new Set));
console.log(result);
You should not use indexOf inside a loop, because it has linear cost, and the total cost becomes quadratic. What I would do is use a map to count the occurrences of each item in your array, and then convert back to an array subtracting one occurrence.
let originalValues = ['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd'];
let freq = new Map(); // frequency table
for (let item of originalValues)
if (freq.has(item)) freq.set(item, freq.get(item)+1);
else freq.set(item, 1);
var arr = [];
for (let [item,count] of freq)
for (let i=1; i<count; ++i)
arr.push(item);
console.log(arr);
If all items are strings you can use a plain object instead of a map.
You can create a simple Array.prototype.reduce loop with a hash table to count the number of occurrences and populate the result only if it occurs more than once.
See demo below:
var originalValues=['a','a','a','a','b','b','b','c','c','d'];
var result = originalValues.reduce(function(hash) {
return function(p,c) {
hash[c] = (hash[c] || 0) + 1;
if(hash[c] > 1)
p.push(c);
return p;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}
Instead of using Set for this you could just use reduce() and create new array with unique values and also update original array with splice().
let oV = ["a", "a", "a", "a", "b", "b", "c", "c", "d"]
var o = {}
var distinct = oV.reduce(function(r, e) {
if (!o[e]) o[e] = 1 && r.push(e) && oV.splice(oV.indexOf(e), 1)
return r;
}, [])
console.log(distinct)
console.log(oV)
As an alternate approach, you can use following algorithm that will remove only 1st entry of a duplicate element. If not duplicate, it will not remove anything.
const originalValues = ['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd'];
var r = originalValues.reduce(function(p, c, i, a) {
var lIndex = a.lastIndexOf(c);
var index = a.indexOf(c)
if (lIndex === index || index !== i)
p.push(c);
return p
}, [])
console.log(r)
If duplicates are not case, then you can directly remove first iteration directly
const originalValues = ['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd'];
var r = originalValues.filter(function(el, i) {
return originalValues.indexOf(el) !== i
})
console.log(r)
I Have a multidimensional array such as
MultArrary = [
['a','b'],
['c','d'],
['f','g']
]
What i need is to get the key and value of each array inside the array and push it into another array
Expected array1 = ['a','c','f'];
expected array2 = ['b','d','g'];
Any ideas how to achieve this with javascript or rxjs will be great
Easiest thing to do (while not syntatically correct, see the comments below your question) in your case is to use a Map (provided you are within an ecmascript6 capable environment):
var MultiArray = [
['a', 'b'],
['c', 'd'],
['f', 'g']
];
var m = new Map(MultiArray);
var index0 = Array.from(m.keys());
var index1 = Array.from(m.values());
console.log(index0, index1);
Using Underscore.js you can do it with unzip:
var MultArrary = [
['a', 'b'],
['c', 'd'],
['f', 'g']
];
var rst = _.unzip(MultArrary);
//[['a','c','f'],['b','d','g']]
console.log(rst);
<script data-require="underscore.js#1.8.3" data-semver="1.8.3" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
You could use a single approach and build the result in one task.
Your wanted result is in pivot[0] and pivot[1].
var multArrary = [['a', 'b'], ['c', 'd'], ['f', 'g']],
pivot = multArrary.reduce(function (r, a) {
a.forEach(function (b, i) {
r[i] = r[i] || [];
r[i].push(b);
});
return r;
}, []);
console.log(pivot);