Sorting a value pair in Javascript - javascript

I must be missing the proper term or else I'm sure I could find the answer by searching... in any case, here's what I want to do.
Through javascript, I get four variables (A, B, C, and D) that I would like to sort, and still keep track of the variable name (since it's encoded with meaning information).
Sample Data:
A = 2;
B = 1;
C = 4;
D = 3;
What I need to do now is sort them in value order (4,3,2,1) such that I can actually know the variable name ordering (C,D,A,B).

You can keep an array of value pair objects and then simply sort that array. Of course, the array's sort method need to know how to interpret the object but that can be done by supplying a comparison function to the sort method.
First declare your array of objects:
sample_data = [
{ name: 'A', value: 2 },
{ name: 'B', value: 1 },
{ name: 'C', value: 4 },
{ name: 'D', value: 3 }
];
Then write a comparison function:
function custom_compare (a,b) {
// I'm assuming all values are numbers
return a.value - b.value;
}
Then simply sort and reverse:
sample_data.sort(custom_compare).reverse();
To print out the sorted names simply iterate through the array:
for (var i=0;i<sample_data.length;i++) {
console.log(sample_data[i].name);
}

May it help you:
https://github.com/shinout/SortedList
This is sortedlist library.

I think what you should be looking for something like "Associative arrays" implemented in Javascript.
Check this earlier thread for your answer.

Related

Deduplicate array of objects by given property name

I have an array of objects with about 1500 elements, I am trying to make a new array removing the elements that have a duplicate unique property. But for some reason when I run the function it stops at the first 100 elements of the array. How can I get it to loop through the whole array.
const result = Array.from(new Set(DATA.map((a) => a.Numbers))).map(
(Numbers) => {
return DATA.find((a) => a.Numbers === Numbers);
}
);
Create an object that uses the Numbers property as the keys. Since object keys must be unique, this will remove duplicates. Then get the object values to convert back to an array.
const DATA = [{ Numbers: 1 },{ Numbers: 2 },{ Numbers: 3 },{ Numbers: 4 },{ Numbers: 1 },{ Numbers: 4 }];
const result = Object.values(Object.fromEntries(DATA.map(a => [a.Numbers, a])));
console.log(result)
You're really complicating matters. You're mapping twice, converting the result into a set, and then creating a new array from that set.
It would be much simpler (and more readable) to use a simple loop, and keep a record of the numbers in the objects. If a number already exists splice the object from the array.
This method won't create a new array - you're modifying the existing one - but it will work.
const arr = [{ number: 1 },{ number: 2 },{ number: 3 },{ number: 4 },{ number: 1 },{ number: 4 }];
const numbers = new Set();
for (let i = arr.length - 1; i >= 0 ; i--) {
const { number } = arr[i];
if (numbers.has(number)) arr.splice(i, 1);
numbers.add(number);
}
console.log(arr);
Since no Map-based answers yet (and I believe, Map suits the purpose the best from performance standpoint), I'll post mine:
const src = [{key: 'a', value: 1}, {key: 'c', value: 3}, {key: 'b', value: 2}, {key: 'a', value: 1}, {key: 'c', value: 3}]
const dedupe = (arr, keyProp) => [
...arr
.reduce((acc, obj) =>
(acc.set(obj[keyProp], obj), acc), new Map)
.values()
]
const result = dedupe(src, 'key')
console.log(result)
.as-console-wrapper{min-height:100%;}
The idiom for making an array of distinct objects (also described in this answer) goes like this:
const distinct = DATA.filter((obj, idx) =>
idx === data.findIndex(a => a.Numbers === obj.Numbers));
This filters the input array by selecting all items that, when linearly searched for, return the same index they already have. Thus selecting the first of each such object with the given criteria.
Note: that some of your Numbers were strings and some were actual numbers. (Those with a leading 0 were stored as strings, like '02'.) You could use the less strict == instead of === if you need to deal with situations where the same value may be stored in both string and number format. e.g.: a.Numbers == obj.Numbers.

JavaScript generator function times out when trying to replicate Python's itertools.combinations

With the help of a couple of answers here I've been able to start learning about generators and develop the following function:
function* icombinations(arr, k) {
function* getCombinations(newArr, shift) {
if (newArr.length === k) {
yield newArr;
}
for (let i = shift; i < arr.length; i++) {
yield* getCombinations([...newArr, arr[i]], i + 1);
}
}
yield* getCombinations([], 0);
return [];
}
Here is a link to repl.it: https://repl.it/E2QW/1
I haven't probably grasped the concept fully since the function above times out for very long inputs as I'm trying to generate all possible combinations first and then yield each one. Would you know how I could refactor the the function so that I don't generate all combinations first?
Here is the description of the challenge that I'm trying to solve:
Write a function called icombinations that should be a generator function with behavior similar to
Python's itertools.combinations. You are given an array arr of unique
items and an integer k.
You should yield each unique combination of elements in arr of length
k with no replacements until there are no possible unique
combinations left, at which point you should terminate the generator
function. Your generator will be called with next(), and in some cases
it will be called until completion.
Additionally It is important that you return combinations in the same
order as the original array arr. (see the example below)....
For example:
given an array of unique elements example_arr and an integer
example_k:
where example_arr = ['a', 'b', 'c', 'd'] and example_k = 2;
calling the next() method of the iterator should return [ 'a', 'b' ].
if we were to call next() again we should get [ 'a', 'c' ] and so
on...
so that if we got all values yielded by the generator we would have
the following:
[ 'a', 'b' ] [ 'a', 'c' ] [ 'a', 'd' ] [ 'b', 'c' ] [ 'b', 'd' ] [
'c', 'd' ] again, notice the order of the above, as you will need to
replicate it in your solution.
Some more things to consider:
If your solution is timing out, it may be because you tried to
generate all possible combinations first and then yield each one.
This defeats the point of a generator. Some of input values will be
large.
Values in arr will always be unique but they may be of different types
(i.e. strings, integers, other objects).
The only cases in which you would not be able to produce combinations
is that in which arr is null or empty or has a length less than k. In
any of those situations you should return an empty array.
You might be able to get better suggestions on Code Review, but one improvement you can try is to prune some of the "dead-end" recursive paths. Since you know that each result must be length k, you should only recurse when you have enough elements left in the source array to actually complete a k-subset.
function* icombinations(arr, k) {
function* getCombinations(newArr, shift) {
if (newArr.length === k) {
yield newArr;
}
// if what's available is >= what's needed
else if (arr.length - shift >= k - newArr.length) {
for (let i = shift; i < arr.length; i++) {
yield* getCombinations([...newArr, arr[i]], i + 1);
}
}
}
yield* getCombinations([], 0);
return [];
}
But without your test cases or limits on arr.length and k, we can't know if this is good enough. You mentioned that arr.length could be 50, which means a maximum of 126,410,606,437,752 subsets when k is 25. No algorithm no matter how efficient will complete that in any reasonable amount of time. Even when k is 5 (or equivalently, 45), you're looking at 2,118,760 combinations.
Another thing you could try is to pre-allocate the subset array (newArr) outside of the inner function and then update the array in-place prior to each recursive invocation. This avoids the need to copy newArr each time you want to append a value to it, but you will still need to yield a copy of newArr in your base case. This, however, is more of a micro-optimization compared to the branch-pruning. Try the pruning first by itself to see how much of improvement each change makes.
Finally, you could also switch to an iterative implementation and see if that works.

why array.sort not work in javascript?

I have array of object .I want if i add object in array it should add in sorted way .I used array to sort .but it not sort my array . here is my code
https://jsfiddle.net/8oczc5x5/
var arr = [{
elem: {
text: function() {
return "aa";
}
}
}, {
elem: {
text: function() {
return "yy";
}
}
}];
var obj = {
elem: {
text: function() {
return "bb";
}
}
}
arr.push(obj);
arr.sort()
console.log(arr[1].elem.text())
Expected Out put
"bb"
Actual output
"yy"
..why ? I used sort it should sort my array ?
sort only really works "out-of-the-box" when sorting character data alphabetically. And why would you expect it to call your functions and compare them? That's really dangerous and complicated. However, you can perform your own special sort by passing it a function.
Taken from the docs (compareFunction is the function you're passing in):
If compareFunction is supplied, the array elements are sorted according to the return value of the compare function. If a and b are two elements being compared, then:
If compareFunction(a, b) is less than 0, sort a to a lower index than b, i.e. a comes first.
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
If compareFunction(a, b) is greater than 0, sort b to a lower index than a.
compareFunction(a, b) must always return the same value when given a specific pair of elements a and b as its two arguments. If inconsistent results are returned then the sort order is undefined.
arr.sort(function(a, b) {
// localeCompare does a string comparison that returns -1, 0, or 1
return a.elem.text().localeCompare(b.elem.text());
});
function sortNumber(num1,num2) {return num1 - num2;} var numbs = [5, 17, 29, 48, 4, 21];
var sortnumb = numbs.sort(sortNumber);
alert(sortnumb)
You have to specify how to sort
arr.sort( (a,b) => a.elem.text().localeCompare(b.elem.text() );

iterate through object using values instead of index

I have an array of mathematical operators stored as an object.
object {0: "-", 1: "*", 2: "/", 3: "+"} called numOperators
I don't know what order the operators will be in, but they need to be execued in the correct order of *, /, +, and - So when I reassign the above object into another parallel object, I assign the indexes of the above object with the order they need to be executed. Then i have this object:
Object {0: 2, 1: 0, 2: 1, 3: 3} called opArray
What I want to do is iterate through the object (which could be any length) by looking at the values instead of the indexes.
In summary, I want to iterate all of the values in the order 3, 2, 1, 0. Look for values of 3 until those are used up, then look for 2, then 1, then finally go through 0. I haven't been able to come up with an efficient way of doing this. Because mathematical operators need to be done in order, a temporary result value is created and then used for the next iteration. Eventually, they are all combined into a single result.
This is what I was trying last:
var valArray = {0: "3", 1: "8", 2: "4", 3: "8", 4: "2"};
var res=[];//temporary result values ordered by execution
var returnRes=0;
var op=0;
$.each(opArr, function(index, value) {//goes through the values in order
if(value==0){
op = numOperators[index]; //uses the indexes that matches the values
res[index]=operate(valArr[index], valArr[index+1],op);
returnRes=res[index];
console.log(res);
}
if(valuei>0){
op = numOperators[index];
res[index]=operate(res[index-1], valArr[index+1],op);
returnRes=res[index];
console.log(res);
}
});
return(returnRes);
I know I may be going about this the completely wrong way, so I'd appreciate some insight on what is an easier way to do this. Thanks!
To clarify further, I have a valid reason for taking this approach to math and not using eval(). Some of the numbers are derived from variables read in as text and converted. There could also be text (non-number text) that needs to be concatenated. So I need to get the math and text separated and evaluated differently. I figured an individual approach would be best.
The apparent solution seems to be using a for each loop. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for_each...in
The other thing you can do and what looks closer to your use case is to write an iterator for this. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
You could make an array and sort it by value:
var opArray = {0: 2, 1: 0, 2: 1, 3: 3};
var array = [];
for (var key in opArray) {
array.push({
key: key,
value: opArray[key]
});
}
array.sort(function(a, b) {
return a.value < b.value;
});
console.log(JSON.stringify(array));
// will print
//[
// {"key":"3","value":3},
// {"key":"0","value":2},
// {"key":"2","value":1},
// {"key":"1","value":0}
//]
// So now you can iterate over the array in the correct order
// and access the key and value properties
Why not use an ordinary array:
var numOperators = ["-", "*", "/", "+"];
The access is via
numOperators.forEach(function (operator) {
// do something
});
possible.
Example
8*4, result/8, 3-result, result+2
var operators = ['*', '/', '-', '+'],
functions = {
'-': function (a, b) { return b - a; }, // spot the changed variables
'*': function (a, b) { return a * b; },
'/': function (a, b) { return a / b; },
'+': function (a, b) { return a + b; }
},
valArray = [8, 4, 8, 3, 2];
document.write(valArray.reduce(function (r, a, i) {
return functions[operators[i]](r, a);
}, valArray.shift()));

Sort array containing objects based on another array [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
JavaScript - Sort an array based on another array of integers
Javascript - sort array based on another array
If I have an array like this:
['one','four','two']
And another array like this:
[{
key: 'one'
},{
key: 'two'
},{
key: 'four'
}]
How would I sort the second array so it’s key property follows the order of the first? In this case, I want:
[{
key: 'one'
},{
key: 'four'
},{
key: 'two'
}]
We can use the sort() function to do this by passing it a custom function which does the comparison. This function has to return 3 possible values given a or b to compare:
return -1 if a is indexed lower than b
return 0 if a is considered equal to b
return 1 if a is indexed greater than b
With this in mind, we can define a function such as this:
function sortFunction(a,b){
var indexA = arr.indexOf(a['key']);
var indexB = arr.indexOf(b['key']);
if(indexA < indexB) {
return -1;
}else if(indexA > indexB) {
return 1;
}else{
return 0;
}
}
This function will take in the objects you defined in your array, and find where that value is in the arr array, which is the array you're comparing to. It then compares the index, and returns the values as needed.
We use this function by passing the function into the sort() function as such:
testArray.sort(sortFunction)
where testArray is the array you're trying to sort.
You can take a look at here, where I did this example, and you can see the second object in your array being "alerted" to you, before and after the sort function was called. http://jsfiddle.net/Sqys7/
Here's my take on it:
function orderArray(array_with_order, array_to_order) {
var ordered_array = [],
len = array_to_order.length,
len_copy = len,
index, current;
for (; len--;) {
current = array_to_order[len];
index = array_with_order.indexOf(current.key);
ordered_array[index] = current;
}
//change the array
Array.prototype.splice.apply(array_to_order, [0, len_copy].concat(ordered_array));
}
Sample implementation:
var array_with_order = ['one', 'four', 'two'],
array_to_order = [
{key: 'one'},
{key: 'two'},
{key: 'four'}
];
orderArray(array_with_order, array_to_order);
console.log(array_to_order); //logs [{key: 'one'}, {key: 'four'}, {key: 'two'}];
The usual fiddle: http://jsfiddle.net/joplomacedo/haqFH/

Categories

Resources