Get the current index in sort function - javascript

What I need to know is a way to get the current index in the compare function of sort method in an array. Suppose this code:
var points = [40, 100, 1, 5, 25, 10];
points.sort(function (a, b) {
return a - b;
//i need the current index of `a` and `b` here
});
In the anonymous function, I need the current index of a and b objects. How can I get it?

Make an array of objects with indices...
var arr = [1,5,2,3,8,13, 1];
var arr2 = arr.map(function(o, i) {return {idx: i, obj: o}; }).sort(function(a, b) {
console.log('a.idx:', a.idx, 'b.idx:', b.idx);
return a.obj - b.obj;
});
for(var i = 0, j = arr2.length; i < j; i++){
console.log('i:', i, 'arr2[i].obj:', arr2[i].obj);
}
fiddle: https://jsfiddle.net/k6xdqpb2/

The index of a or b?
var indexOfA = points.indexOf(a);
This will give you the index that a first appears in the array.
Depending on what you are trying to do, another option may be to use a map for sorting as described in more details under the 'Sorting with map' heading here. An example of this approach is given in deostroll's answer.

Related

Sort 2D array by matching the last values with the first one in the next index

So basically, I have this array
array = [[1,0],[2,1],[0,3],[3,2]]
Is there any quick method to convert the array to look like this
array = [[0,3],[3,2],[2,1],[1,0]]
What I want is for the first element of the new array to be always contain 0 in the first spot of the nested array. That's easy enough, because the sort() function does exactly that; the hard part is ordering the new array like the one above.
In the most simplest terms, I'd like for nested arrays to be "connected": see how the 3 of the first nested array matches the other 3 to its right and so on.
Feel free to leave any comments so I can try to explain the problem a little bit better.
For the example you gave the easiest solution would be to sort the 2d array by the second element of each inner array, as follow:
let array = [[1,0],[2,1],[0,3],[3,2]];
array.sort((a, b) => b[1] - a[1]);
In that way you can sort the array with the sort method according to the elements in the inner arrays.
let array = [[1,0],[2,1],[0,3],[3,2]];
array.sort((a, b) => b[1] - a[1]);
console.log(array);
You could take an object as reference and rebuild the array by taking the chained items.
const
getItems = (reference, value) => {
const a = reference[value];
return a ? [a, ...(a[1] === 0 ? [] : getItems(reference, a[1]))] : [];
},
array = [[1, 0], [2, 1], [0, 3], [3, 2]],
reference = array.reduce((r, a) => (r[a[0]] = a, r), {}),
result = getItems(reference, 0);
console.log(result);
Look at this method:
const array = [[1,0],[2,1],[0,3],[3,2]];
const result = [...array];
// Put the subarray with the zero element first
// You can use the sort() function but I guess this method
// performs better in terms of time
for (let i = 0; i < result.length; ++i) {
if (result[i][0] === 0) {
result.unshift(...result.splice(i, 1));
break;
}
}
// Now reorder the array so that the last index of a subarray
// matches with the first index of the other subarray
for (let i = 0; i < result.length; ++i) {
for (let j = i + 1; j < result.length; ++j) {
if (result[i][1] === result[j][0]) {
// recollocate the subarray so that it matches the way we want
result.splice(i + 1, 0, ...result.splice(j, 1));
break;
}
}
}
console.log(result)

javascript push an item into list index by value

Lets say I have a list:
var list = []
Now I want to insert some value into the list in a way that its index should be according to its value
list.push(6)
list.push(2)
This will give me a result of [6, 2]
But what I want is its index should be managed according to its value.
Here 2 is smaller than 6 so 2 should come first and give result like
[2, 6] . And if again I do list.push(1) it should give result like [1,2,6] and so on.
How can I achieve this in javascript ?
You can use Array#sort.
var list = [];
list.push(6);
list.push(2);
list.push(1);
list.sort(function(a, b) {
return a - b;
});
console.log(list);
You simply need to use Array sort function. As it treats array items as string and does not sort integers correctly by default, you need to use custom compare function for this:
var arr = [1, 22, 6, 2 ];
arr.sort(function(a, b){
return a - b;
});
console.log( arr );
You can use the sort() function.
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();
The result of fruits will be:
Apple,Banana,Mango,Orange
Edit:
Sorry, for numbers this solution does not work. You can use this:
Sort numbers in an array in ascending order:
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return a-b});
The result of points will be:
1,5,10,25,40,100
We can override push function of list object.
var list = [];
var copyPush = list.push.bind(list);
list.push = function(){
var toret = copyPush.apply(this,arguments);
this.sort(function(a,b){ return a-b});
return toret;
}
list.push(1);
list.push(3);
list.push(2);
list.push(5);
console.log(list); //[1, 2, 3, 5]
These other answers are missing the point, they assume that the list is already populated, and then you push in. What you need to do is compare the number you are going to push into the array, with the array itself, splicing the value in like so:
arr = [1,5,7];
var number = 0;
function findValue(value) {
return function(element, index, array) {
return (element <= value);
}
}
var filtered = arr.filter(findValue(number))
index = arr.indexOf(filtered[filtered.length-1]) +1;
arr.splice(index, 0, number);
alert(arr);
Here's a working fiddle:
https://jsfiddle.net/GerardSimpson/h3t6vcka/

breaking an array into subsets

I am trying to get this function to split an array into subsets. each subset is to have numbers that are equal to the previous or within 1 from the previous number.
The example I have below should return two subsets but it returns {0, 1, 2, 3} instead. Any idea on what I am doing wrong? Also, is there a better way to dynamically create an array for each new subset? Thanks
function max_tickets() {
var arr = [4, 13, 2, 3];
var myarr = arr.sort(function(a, b){return a-b});
for(var i = 0; i<myarr.length; i++){
var iplus = i+1;
if(i === i || i === iplus){
newArr= [];
newArr.push(i);
}else if (i !== i || i !== iplus){
arr2 =[];
arr2.push(i);
}
}
}
What you are trying to do is usually called "partitioning". The generic version of the problem is to partition an array into sub-arrays using some "rule", or predicate, or condition, which specifies which partition a particular element is supposed to go into, or specifies that it should go into a new partition.
The pseudo code for doing this would be:
To partition an array:
Initialize the resulting array
For each element in the array
If that element starts a new chunk
Create a new empty chunk in the resulting array
Add the element to the most recent chunk
Return the result
This can be expressed in JS quite straightforwardly as
function partition(array, fn) {
return array.reduce((result, elt, i, a) => {
if (!i || !fn(elt, i, a)) result.push([]);
result[result.length - 1].push(elt);
return result;
}, []);
}
Now we need to write the function saying when a new partition should start:
// Is the element within one of the previous element?
function close(e, i, a) {
return Math.abs(e - a[i-1]) > 1;
}
We can now partition the array with
partition([[4, 13, 2, 3], close)
This should work.
function max_tickets() {
var arr = [4, 13, 2, 3];
var myarr = arr.sort(function (a, b) { return a - b });
arrSubsets = [];
arr1 = [];
for (var i = 0; i < myarr.length; i++) {
if (myarr[i - 1] === undefined) {
arr1.push(myarr[i]);
continue;
}
if (myarr[i] - myarr[i - 1] <= 1) {
arr1.push(myarr[i]);
}
else {
arrSubsets.push(arr1);
arr1 = [];
arr1.push(myarr[i]);
}
}
if (arr1.length > 0)
arrSubsets.push(arr1);
}
max_tickets();
Based on your questions:
Any idea on what I am doing wrong?.
Inside of your loop you are using i as if it is the value of the array, but the loop goes from 0 to the value of myarr.length in your particular case 4, so that makes the value of i to be 0, 1, 2, 3.
As you can see you are using the values of the index to compare, instead of using the values of the array in order to use the values of the array you must specify the arrayname[index], in your case myarr[i] that will give you the values: 4, 13, 2, 3.
Also, is there a better way to dynamically create an array for each new subset?
Yes you can create an array inside of another array dynamically inside of a loop:
var b = [];
for(var i = 0; i < 10; i++){
b.push(['I am' + i, i]);
}
As you can see in the previous example I'm creating an array inside of the b array so once the loop finishes the b array will have 10 arrays inside of it with 2 elements each.

Callbacks & manipulating arrays but getting undefined back

Practicing callbacks & higher ordered function & found this question online.
var merge = function(array1, array2, callback){
//your code here.
}
var x = merge([1, 2, 3, 4], [5, 6, 7, 8], function(a, b){
return a + b;
});
//x should now equal [6, 8, 10, 12].
Here's my take on this problem.
var merge = function(array1, array2, callback){
for(var i = 0; i < array1.length; i++) {
callback(array1[i], array2[i]);
}
}
var x = merge([1, 2, 3, 4], [5, 6, 7, 8], function(a, b){
return a + b;
});
When I console.log(x), the console returns "undefined" so I'm guessing it has to do w/ the value of x not being an array. I can see that the math is being done correctly though, for when I change "return a + b" to "console.log(a + b)" I get the right numbers but just not in array form. Can anyone point me towards the right direction?
You are calling the callback, but you are ignoring the value returned by it. You should accumulate all the values in an array and your should return the array from merge.
For example,
function merge(array1, array2, callback) {
// Define an array object to accumulate the results from `callback`
var result = [];
for (var i = 0; i < array1.length; i++) {
// Accumulate the result of `callback` in `result` array
result.push(callback(array1[i], array2[i]));
}
// Return the `result` array
return result;
}
Note: If the arrays are of different sizes then running the loop based on array1's length will not be correct always. So, you might want to either
go with the smallest length of two arrays and ignore elements from the longer array
or use a default value for the elements of the shorter array.
If you choose go with the first method, then you just need to adjust the loop condition, like this
var minLen = Math.min(array1.length, array2.length);
for (var i = 0; i < minLen; i++) {
...
If you choose to go with the second method, then you need to run till the maximum of two arrays and use default values, like this
var maxLen = Math.max(array1.length, array2.length);
for (var i = 0; i < maxLen; i++) {
result.push(callback(array1[i] || 0, array2[i] || 0));
}
Here, if the value of array1[i] returns undefined (if the index is not found in an array, undefined will be returned), it means that array1 is shorter than array2, so the default value 0 will be used.

How to get subset of two arrays in javascript?

What I am trying to do is if I have Array
a = {1,2,3,4};
b = {1,2};
Then I want subset array as c = {3,4};
Can anybody help me?
a = [1, 2, 3, 4]
b = [2, 1, 5]
comp = a.filter(function(e) { return b.indexOf(e) < 0 })
see Array.filter and Array.indexOf for more details and degradation options.
I'm not aware of any built-in way to do this, you basically have to loop through c and check whether each element is in a and, if so, remove it. The Array#indexOf method can help you with checking, but not all implementations have it (though most do). Removal can be via Array#splice.
So:
var a, c, index;
a = [1, 2];
c = [1, 2, 3, 4];
for (index = c.length - 1; index >= 0; --index) {
if (a.indexOf(c[index]) >= 0) {
c.splice(index, 1);
}
}
...and then either supply your own implementation of Array#indexOf if your environment doesn't support it, or use a library like Prototype that supplies it for you (jQuery gives it to you as well, but through its own jQuery.inArray function). If doing it yourself:
if (!Array.prototype.indexOf) {
(function() {
Array.prototype.indexOf = Array_indexOf;
function Array_indexOf(elm) {
var index;
for (index = 0; index < this.length; ++index) {
if (this[index] === elm) {
return index;
}
}
return -1;
}
})();
}
Note that adding to the Array prototype as above can be dangerous when done with poorly-written code code that makes assumptions about the environment. Specifically, code that treats for..in as though it loops through array element indexes (it doesn't, it looks through object property names) will get messed up if you add to the Array prototype. (That's probably why jQuery doesn't do it.)
Live example
Assuming that you're after the relative complement of b in a.
function complement(a, b) {
// convert A to an associative array
var myHash = {};
for (var i = 0; i < a.length; ++i) {
myHash[a[i]] = 1;
}
// remove the elements that exist in B
for (var i = 0; i < b.length; ++i) {
delete myHash[b[i]];
}
// what's left is A \ B
// assumes that no-one broke Array by adding new properties to the prototype
return Object.keys(myHash);
}
// test
var a = [1, 2, 3, 4];
var b = [1, 2];
var c = complement(a, b);
alert(c);
This should scale well for larger arrays, since it uses hash table indexing rather than linear searches to remove the unwanted elements.
Here is another solution which uses Array.filter() and Array.includes()
function arrayDifference(a, b) {
return a.filter((x) => !b.includes(x));
}
const a = [1, 2, 2, 2, 3, 4]
const b = [1, 2]
arrayDifference(a,b) // returns [3, 4]

Categories

Resources