suppose I have an array in JavaScript as written below :
Array:[
["0", "Grape"],["0", "Orange"],["1", "Mango"],["2", "Strawberry"],
["2", "Banana"],["3", "Watermelon"]
]
that I want to reconstruct as :
Array:[
["Grape", "Orange"],["Mango"],["Strawberry", "Banana"],["Watermelon"]
]
The numbers in initial array acts as indexes of fruits' data in reconstructed array. So, Grape and Orange are placed in index 0, Mango in index 1, and so on. How do I achieved this? Thank you.
Use Array.reduce and Object.assign
Using reduce, we are creating the resultant array where for each entry in original array, we are adding / updating the value for an index (c[0]).
let arr1 = [["0", "Grape"],["0", "Orange"],["1", "Mango"],["2", "Strawberry"],["2", "Banana"],["3", "Watermelon"]];
let arr2 = arr1.reduce((a,c) => Object.assign(a, {[c[0]]:(a[c[0]] || []).concat(c[1])}), []);
console.log(arr2);
a is your initial array:
Here I supposed that indices start at 0, are integers and are sorted.
a = [["0", "Grape"],["0", "Orange"],["1", "Mango"],["2", "Strawberry"],["2", "Banana"],["3", "Watermelon"]]
b=[];
for (i in a) {
if (a[i][0] >= b.length)
b.push([]);
(b[b.length-1]).push(a[i][1]);
}
Related
'I wish to sort an array in numerical order but once it is sorted I wish to be able to find the original index.
For example the original array:
ptsGP = [3,8,2,5,6,9,8,4]
I am using the following code below to sort the array:
arr = ptsGP;
var arr2 = arr.map(function(o, i){return {idx: i, obj: o}; }).sort(function(a, b) {
return b.obj - a.obj;
});
for(var i = 1, j = arr2.length; i <= j; i++){
document.write('i:' + i + ' = arr2[i].obj: PTS: ', arr2[i-1].obj+"<br/>");
}`
This is fine as the sorted array is :
arr = [2,3,4,5,6,8,8,9];
How can I find the index of sorted number in the original array? In this case it would be :
Index on original array would be = [2,0,7,3,4,1,6,5]
I know I could use map on the original array but how can I deal with duplicate numbers i.e, in this case I have two number 8's within the array?
You can achieve it by following below steps :
Creating a deep copy of an original array by using spread operator. So that we can get proper indexing.
Now we can iterate deep copy array to get the index of the elements from an original array.
Regarding duplicate values we can check via .indexOf() and .lastIndexOf() methods.
via and then via comparison. For fetching the correct index of duplicate values I wrote a logic based on the count of duplicate value.
Working Demo :
// Original array.
const originalArray = [3, 8, 2, 5, 6, 9, 8, 4];
// Creating a deep copy of an original array.
const deepCopy = [...originalArray].sort(function(a, b){
return a-b
});
// result array
const arr = [];
// count to get the index based on duplicate values.
let count = 0;
// Iterating deepCopy array to get the actual index.
deepCopy.forEach((elem) => {
// Checking for duplicate value in an array
if (originalArray.indexOf(elem) === originalArray.lastIndexOf(elem)) {
// This line of code execute if there is no duplicates in an array.
arr.push(originalArray.indexOf(elem))
} else {
// This line of code execute if there is duplicate values in an array.
count++;
// Inserting the index one by one.
arr.push(originalArray.indexOf(elem, count))
}
});
// Result array.
console.log(arr);
How can I made new array from firsts elements of arrays from this array ?
[["1",2],["3",2],["6",2]]
and I want it to be
['1', '3', '6']
My attempt:
var newArray = []
for (i = 0; i < arrayToCompare.length - 1; i++) {
newArray.push(arrayToCompare[[0]])
}
You could just use a simple map and destructure the first element:
const arr = [["1", 2],["3", 2],["6", 2]]
console.log(arr.map(([e]) => e))
The ([e]) part of that before the => is destructuring the parameter using array destructuring. It means that for each subarray passed to the map callback, e receives the value of the first element of the subarray. In ES5 and earlier, the ([e]) => e arrow function would be function(entry) { return entry[0]; }
Still, if you still don't understand the concept, prefer efficiency, or just want to go back to basics, you could use the trusty for loop, making sure to push only the first element of each subarray:
const arr = [["1", 2],["3", 2],["6", 2]]
const output = []
for (let i = 0; i < arr.length; i++) {
output.push(arr[i][0])
}
console.log(output)
Try this:
let arr = [["1", 2], ["3", 2], ["6", 2]];
let res = arr.map(val => {
return val[0]
})
console.log(res);
You can use Array.prototype.map() to crate a new array with the item from the first index:
var arr = [["1",2],["3",2],["6",2]]
var newArray = arr.map(i => i[0]);
console.log(newArray);
This one also works
console.log(Object.keys(Object.fromEntries([["1", 2],["3", 2],["6", 2]])))
In this example, Object.fromEntries will create an object from an array of key/value pairs - it will take the first element as a key, and the second element as the value - creating something like this:
{
"1": 2,
"3": 2,
"6": 2
}
Then, Object.values will grab the keys of the object, thus, removing the values and retaining the keys, giving the desired output.
P/S: just added another way to do this
console.log(Array.from([["1", 2],["3", 2],["6", 2]], x=>x[0]))
Use map and get the first element using shift method.
PS: not very efficient because of ...(spread) operator for each element.
const arr = [["1",2],["3",2],["6",2]];
const arrFirsts = arr.map(items => [...items].shift());
console.log(arrFirsts)
console.log(arr)
I have an array which looks like:-
[[0,1], [0,2], [0,3], [1,1], [1,2]...]
I am looking to remove one of the arrays from this array based on the indexOf() but I keep getting a value of -1, which removes the last item from the array when I try the following code:-
array = [[0,1], [0,2], [0,3], [1,1], [1,2]];
console.log('Removed value', array.splice(array.indexOf([0,3]), 1));
console.log('Result', array);
would somebody be able to point me in the right direction to help solve this issue I am having?
Thank you in advance.
You can't use indexOf because when you declare [0,3] in array.splice(array.indexOf([0,3]), 1)) you're creating a new array and this new object is not inside your array (but rather another array that has the same values).
You can use findIndex instead as follows (example):
array.findIndex(x => x[0] === 0 && x[1] === 3)
this will return 2 - now you can use it to delete:
array.splice(2, 1)
If it is OK to remove every occurrence of [0,3], then consider Array.filter combined with array destructuring of the lambda arguments. It offers a slightly leaner syntax than the other solutions.
const input = [
[0,1],
[0,2],
[0,3],
[1,1],
[1,2]
];
const result = input.filter(([x,y]) => !(x==0 && y==3));
console.log('Result=', result);
To explain why your solution will not work:
Comparison operators only work for values not passed by a reference. When dealing references, comparison operators always return false, unless the two references point to the same object. (See this on MDN)
An example:
a = [0,1]
b = a
b === a //true. a and b point to the same array.
a === [0,1] //false. a points to a different array than [0,1]
b[0] = 2
a[0] //2 - b points to the same array as a
To give you a solution (borrows from here)
//Function to compare the values inside the arrays, and determine if they are equal.
//Note: does not recurse.
function arraysEqual(arr1, arr2) {
if(arr1.length !== arr2.length)
return false;
for(var i = arr1.length; i--;) {
if(arr1[i] !== arr2[i])
return false;
}
return true;
}
array = [[0,1], [0,2], [0,3], [1,1], [1,2]];
//Find the index where x has the same values as [0,3]
array.findIndex(x => arraysEqual(x, [0,3])) //2
There were a lot of questions asked about this topic, but I couldn't find the answer that addressed directly the issue I am having.
Here is one: Find common elements in 1 array using Javascript
The first difference is that I have a different type of array, its elements are objects with key-value pair, where key is the string and the value is an array of integers.
The second difference is that array is dynamic meaning that sometimes it may have zero elements and the other times it may have 3 object elements.
I am sharing the sample array below:
const array = [
{"key1":[1,2,3]},
{"key2":[2,3,4]},
{"key3":[2,5,6]},
];
The third difference is that the order of elements matters so that final result should output the values of the first element that exist in all subsequent arrays.
The result should be:
const result = [2];
Since 2 is the only common integer of these three elements.
As mentioned array sometimes might have just 1 or 2 or no elements in it and those cases should be accounted.
Edit 1: as asked in the comments the values of array are unique
Since a value can appear in array only once, you can concat the arrays, count the number of appearances, and filter our those that are not equal to the length of the original array.
const findRecuring = (array) =>
[...
[].concat(...array.map((o) => Object.values(o)[0])) // combine to one array
.reduce((m, v) => m.set(v, (m.get(v) || 0) + 1), new Map()) // count the appearance of all values in a map
] // convert the map to array of key/value pairs
.filter(([, v]) => v === array.length) // filter those that don't appear enough times
.map(([k]) => k); // extract just the keys
/** Test cases **/
console.log('Several:', findRecuring([
{"key1":[6,1,2,3,8]},
{"key2":[2,6,3,4,8]},
{"key3":[2,5,6,8]},
]).join());
console.log('None: ', findRecuring([
{"key1":[9,0,11]},
{"key2":[2,6,3,4,8]},
{"key3":[2,5,6,8]},
]).join());
const array = [
{"key1":[1,2,3]},
{"key2":[2,3,4]},
{"key3":[2,5,6]},
];
You could iterate over and store how often a value appears in the array for each value:
var common=new Map();
array.forEach(function(obj){
//var values=new Set(Object.values(obj)[0]);//make unique values out of array
var values=Object.values(obj)[0];//no need for uniqueness as OP states that they are already unique..
values.forEach(function(val){
common.set(val,(common.get(val)||0)+1);
});
});
Now youve got a map with all elements and their appearance in the main array. So now you can simply compare:
var result=[];
common.forEach(function(appearance,el){
if(appearance===array.length){
result.push(el);
}
});
http://jsbin.com/xuyogahija/edit?console
You could get first the arrays in an array without using different keys and then lookup each element if it is in the other array.
let array = [{ key1: [1, 2, 3] }, { key2: [2, 3, 4] }, { key3: [2, 5, 6] }],
result = array
.map(o => o[Object.keys(o)[0]] || [])
.reduce((a, b) => a.filter(c => b.includes(c)));
console.log(result);
I have an array. I sort it.
I get a second array which is already sorted based on the first one.
I need to reverse the sorting on the second array.
For example, if the first array (unsorted) is: [9, 5, 3, 0, 2] then I want to to sort it, so that it becomes [0, 2, 3, 5, 9].
Then I receive the second array sorted based on the first one, for example ["home", "car", "train", "pc", "mouse"]. I need it to become ["mouse, "pc", "train", "home", "car"].
I can't make a copy of the array.
I have the following code:
//data_r is an array with values
var i = 0;
var sort_order = new Array();
data_r.sort(function (a,b) {
var res = a[0] - b[0];
sort_order[i] = res;
i++;
return res;
});
In the end, the the sort_order array will contain the actions performed when we sorted items. If I want to sort a second array exactly the same way as the first then I can do the following:
//data_x is an array with values
var i = 0;
data_x.sort(function (a,b) {
i++;
return sort_order[i-1];
});
Now the data_x array is sorted exactly the same way as the data_r array.
How can I undo sort on the data_r array?
The following code is incorrect:
var unsort = new Array();
for(var i = 0; i < data_r.length; i++)
unsort[i] = sort_order[i]*(-1);//-1 so we perfom the oposite action
Your premise here is flawed.
In the end, the sort_order array contains the actions performed when we sorted items.
No, it doesn't; it contains a log of the comparisons performed by the Javascript Array.sort function. The actions it took in response to those comparison results are private to it.
If I want to sort a second array exactly the same way as the first then I can do the following:
This is not guaranteed to work. Even if the two arrays are the same size, Array.sort may not always compare the same elements in the same order each time it's called - it's possible that it's using a randomized algorithm, that it performs comparisons based on other data that are internal to the interpreter, or that it switches between multiple entirely different sort algorithms under some circumstances.
While this code may work for you, right now, in your current web browser, it is likely to fail in surprising ways in other circumstances (possibly in future browsers). Do not use this technique in production code.
The question is, how can i unsort the data_r array?
Make a copy of the array before you sort it.
Storing res[i] = a - b is like journaling the sort() algorithm - but what if it used a random pivot?
This code is inherently unreliable unless you write sort() yourself. It's also inefficient.
A better approach, one that will solve both your needs, is to create an array of indices and sort that. This is trivial to invert. Then you can implement a permute function that takes an array of indices, and it achieves a sort or unsort, depending on the input.
If x is from 0:n-1, create an array sort_i of same size, then initialize each sort_i[i] = i.
for(var i = 0; i < n; i++)
sort_i[i] = i;
Then
sort_i.sort(function (a,b) { return x[a] - x[b]; });
Now you have the indices. To apply to x:
for(var i = 0; i < n; i++)
sort_x[i] = x[sort_i[i]];
To unsort it, first invert the indices
for(var i = 0; i < n; i++)
unsort_i[sort_i[i]] = i;
Then apply the indices. Exercise left to question asker.
This approach of sorting an array of integer indices is needed when you don't want to move the original elements around in memory (maybe they are big objects), and many other circumstances. Basically you are sorting pointers. The result is an index to the data, and a reverse index.
See #duskwuff's answer on why your approach doesn't work.
Instead, just introduce a mapping between the original data and the sorted data.
{0:2, 1:3, 2:1, 3:0}
Which means the first element became the third, the second became the last and so on. Below we'll use an array instead of an object.
Why does this map help? You can sort it like another dataset by just using the indizes in it as pointers to the data you're going to compare. And you can apply the mapping easily on other datasets. And you can even reverse that mapping very easily. See it in the code:
// data_r, data_x are arrays with values
var l = data_r.length;
var sort_order = new Array(l);
for (var i=0; i<l; i++) sort_order[i] = i; // initialised as 1-1 mapping
// change the sort_order first:
sort_order.sort(function (a,b) {
// a and b being indices
return data_r[a] - data_r[b];
});
// Making a new, sorted array
var data_x_sorted = new Array(l);
for (var i=0; i<l; i++)
data_x_sorted[ sort_order[i] ] = data_x[i]; // put it to sorted position
If you want to sort the data_x array itself, just use the "apply" algorithm which I showed for data_r.
The question is, how can I undo sort on the data_r array?
Either don't sort it at all, and just make a copy of it which gets sorted (or do nothing at all).
Or use the sort_order to reverse it. You just would need to swap i and newIndex (sortOrder[i]) everywhere. Example for building a new, "unsorted" (old-order) array:
var unsorted = new Array(l);
for (var i=0; i<l; i++)
unsorted[i] = data_r[ sort_order[i] ]; // take it from its new position
While this question is 8 years old at this point, I came across it when trying to find the same solution to the problem and I was unable to find a suitable, performant, and intuitive way of doing so, so I wrote one myself.
Please take a look at the sort-unwind library. If ranks is a list of indexes that would rank an array in order...
import unwind from 'sort-unwind'
const suits = ['♥', '♠', '♣', '♦']
const ranks = [2, 0, 3, 1]
const [sortedSuits, tenet] = unwind(ranks, suits)
// sortedSuits <- ['♠', '♦', '♥', '♣']
// unwind <- [1, 3, 0, 2]
You can then use the tenet variable that's returned to unsort an array and restore the original ordering.
const names = ['spades', 'diamonds', 'hearts', 'clubs']
const [tenetNames, tenetRanks] = unwind(tenet, names)
// tenetNames <- ['hearts', 'spades', 'clubs', 'diamonds']
// tenetRanks <- [2, 0, 3, 1]
The sort function just returns a number which can be positive,zero, or negative telling it if the current element goes before,has same weight, or goes after the element it is comparing it too. I would imagine your sort order array is longer than your data_r array because of the number of comparisons you make. I would just make a copy of data_r before you sort it and then set data_r equal to that array when you want it unsorted.
If you have a lot of these arrays to maintain, it might be as well to
convert array1 into an array of objects, each one containing the value
and its original position in the array. This keeps everything together
in one array.
var array1 = [9, 5, 3, 0, 2];
var array2 = ["home", "car", "train", "pc", "mouse"];
var sort = function(array){
var indexed_objects = array.map(function(value, index){
return {index: index, value: value};
});
indexed_objects.sort(function(a,b){
return a.value <= b.value ? -1 : 1;
});
return indexed_objects;
};
var sorted1 = sort(array1);
sorted1; // [{index: 3, value:0}, {index: 4, value: 2}, ...]
And now, given an array of sorted objects, we can write a function to
unsort any other array accordingly:
var unsort = function(array, sorted_objects){
var unsorted = [];
sorted_objects.forEach(function(item, index){
unsorted[item.index] = array[index];
});
return unsorted;
};
var array2_unsorted = unsort(array2, sorted1);
array2_unsorted; // ["mouse", "pc", "train", "home", "car"]
v1 = [0,1,2,3,4,5,6]
q = v1.length
b = []
for(i=0;i<q;i++){
r = parseInt(Math.random()*v1.length)
b.push(v1[r])
a = v1.indexOf(v1[r])
v1.splice(a,1)
}