.sort not sorting from lowest to highest - javascript

while (true) {
let texts = await page.evaluate(() => {
let data = [];
let elements = document.getElementsByClassName("my-2 card__price tw-truncate");
for (var element of elements) {
var floor = Number(element.textContent.split("SOL")[0])
data.push(floor)
}
return data.sort()
});
floorpricearray = texts
if (texts !== undefined) {
console.log(floorpricearray)
}
}
The output
[
10, 11, 5.3, 5.3,
5.38, 5.4, 5.4, 5.4321,
5.4321, 5.5, 5.6942, 5.8,
5.95, 6.2, 7, 7.95,
7.99, 8.05, 8.3, 9
]

You need to give the native .sort method a comparator function like so, otherwise the values will converted to strings and then sorted by the characters ASCII value.
data.sort((a, b) => {
return a - b;
});

You can try this
var a = [10, 11, 5.3, 5.3,
5.38, 5.4, 5.4, 5.4321,
5.4321, 5.5, 5.6942, 5.8,
5.95, 6.2, 7, 7.95,
7.99, 8.05, 8.3, 9
];
a.sort(function(a, b) {
return a - b;
});
alert(a);

It is sorting the array considering the array elements as string. To get it sorted from lowest to highest it needs to be a number.

Related

Why is my JS recursion function returning a list populated with the same entry?

I've been learning Python at school, and I am learning JavaScript on my own time and tackling some JS projects. I can't figure out why my recursion function is only a list with the same entry.
Function description:
The function takes in a list of course Objects, with key-value pairs "courseCode": string and "possibleCombos": list[number]. I want my recursive function to output another list of Objects, with the course Object's "courseCode" value as its keys, and one element of the "possibleCombos" as its value. The returned list will have all the possible permutations of the Objects with course-combo pairs. The function also takes in an Object parameter, for recursion purposes.
Example data:
const dummyObject1 = {
'courseCode': 'BLUE',
'possibleCombos': [1, 2, 3, 4, 5]
}
const dummyObject2 = {
'courseCode': 'RED',
'possibleCombos': [11, 22, 33, 44]
}
const dummyObject3 = {
'courseCode': 'PURPLE',
'possibleCombos': [111, 222, 333, 444, 555, 666]
}
const dummyList = [dummyObject1, dummyObject2, dummyObject3]```
I ideally want:
let dummySchedules = recursionFunction(dummyList, {})
console.log(dummySchedules)
//ideal console output
[
{'BLUE': 1, 'RED': 11, 'PURPLE': 111},
{'BLUE': 1, 'RED': 11, 'PURPLE': 222},
{'BLUE': 1, 'RED': 11, 'PURPLE': 333},
... //and so on.
]
However, the list output I get, is just 120 entries of the same Object.
Here is my code:
function recursiveFunction(listOfCourses, dictSoFar) {
//base case, checks if listOfCourses is empty
if (!listOfCourses.length) {
return [dictSoFar]
} else {
//recursive step
var arraySoFar = [] //accumulator
//iterate through each element of listOfCourses[0]['possibleCombos']
for (let combo of listOfCourses[0]['possibleCombos']) {
//update dictSoFar entry.
dictSoFar[listOfCourses[0]['courseCode']] = combo
//filter out the course we just entered into dictSoFar.
let course = listOfCourses[0]
var cloneListOfCourses = listOfCourses.filter(item => item !== course)
//recursive call, this time with the filtered out list. If we keep following the
//the recursive call down, it should reach the point where listOfCourses is empty,
//triggering the base case. At that point, dictSoFar already has all course: combo
//pairs. This should traverse through all possible course: combo pairs.
var result = recursiveFunction(cloneListOfCourses, dictSoFar)
//update the accumulator
arraySoFar.push(...result)
}
return arraySoFar;
}
}
What is happening? On theory I think the logic makes sense, and I can't tell where its going wrong.
you can do something like this
if you need some explanation fell free to ask
const dummyObject1 = {
'courseCode': 'BLUE',
'possibleCombos': [1, 2, 3, 4, 5]
}
const dummyObject2 = {
'courseCode': 'RED',
'possibleCombos': [11, 22, 33, 44]
}
const dummyObject3 = {
'courseCode': 'PURPLE',
'possibleCombos': [111, 222, 333, 444, 555, 666]
}
const dummyList = [dummyObject1, dummyObject2, dummyObject3]
function recursiveFunction(listOfCourses) {
const loop = (data, acc) => {
if (!data.length) { // if listOfCourses is falsy
return acc
}
const [next, ...rest] = data
if(acc.length === 0){
return loop(rest, next)
}
return loop(rest, next.flatMap(n => acc.flatMap(a => Object.assign({}, a, n))))
}
const courseCombo = listOfCourses.map(({
courseCode,
possibleCombos
}) => possibleCombos.map(c => ({
[courseCode]: c
})))
return loop(courseCombo, [])
}
console.log(recursiveFunction(dummyList))
I came out with a simpler solution that doesn't involve recursion at all
it's divided in two steps:
the first transformation map you dummy object in an array of elements with this form
[{ BLUE : 1}, { BLUE : 2},{ BLUE : 3}, { BLUE : 4}, { BLUE : 5}]
then using reduce it merges all combination of the three arrays together
const dummyObject1 = {
'courseCode': 'BLUE',
'possibleCombos': [1, 2, 3, 4, 5]
}
const dummyObject2 = {
'courseCode': 'RED',
'possibleCombos': [11, 22, 33, 44]
}
const dummyObject3 = {
'courseCode': 'PURPLE',
'possibleCombos': [111, 222, 333, 444, 555, 666]
}
const dummyList = [dummyObject1, dummyObject2, dummyObject3]
const result = dummyList
.map(({courseCode, possibleCombos}) => possibleCombos.map(c => ({[courseCode]: c})))
.reduce((res, item) => res.flatMap(r => item.flatMap(i => Object.assign({}, r, i))))
console.log(result)
What you're looking for is usually called the Cartesian Product of the lists. With a little fiddling, we can turn your inputs into arrays like [{BLUE: 1}, {BLUE: 2}, /*...,*/ {BLUE: 5}], then do a cartesian product of your collection of these to get something like [[{BLUE: 1}, {RED: 11}, {PURPLE: 111}], [{BLUE: 1}, {RED: 11}, {PURPLE: 222}, /...,*/ [{BLUE: 5}, {RED: 44}, {PURPLE: 666}]]. Then we can just call Object.assign on each of these arrays to get your final result.
The code ends up fairly simple.
const cartesian = ([xs, ...xss]) =>
xs == undefined ? [[]] : xs .flatMap (x => cartesian (xss) .map (ys => [x, ...ys]))
const spreadCombos = ({courseCode, possibleCombos}) =>
possibleCombos .map (v => ({[courseCode]: v}))
const combine = (os) =>
cartesian (os .map (spreadCombos)) .map (xs => Object .assign ({}, ... xs))
const dummyObject1 = {courseCode: 'BLUE', possibleCombos: [1, 2, 3, 4, 5]}, dummyObject2 = {courseCode: 'RED', possibleCombos: [11, 22, 33, 44]}, dummyObject3 = {courseCode: 'PURPLE', possibleCombos: [111, 222, 333, 444, 555, 666]}
const dummyList = [dummyObject1, dummyObject2, dummyObject3]
console .log (combine (dummyList))
.as-console-wrapper {max-height: 100% !important; top: 0}
cartesian does the cartesian product of an array of arrays.
spreadCombos does that first transformation from your input into [{BLUE: 1}, {BLUE: 2}, /*...,*/ {BLUE: 5}]
And our main function combine first calls spreadCombos on each input element, calls cartesian, and then for each resulting array, calls Object.assign.
Note that we have to start our Object .assign calls with an empty object. In the intermediate format, the instances of, say, {BLUE: 1} are all references to the same object. If we simply spread our array as the only parameters to Object .assign, then we'd be modifying the same reference each time.
This also helps explain what's wrong with your function. You pass through dictSoFar as a reference to an object, and so continually update that same object. You can fix this by passing a clone of the object in your recursive call. For this purpose, we can make do with the shallow clone {...dictSoFar}, although other circumstances might require a deeper clone. So this patch should fix your approach:
- var result = recursiveFunction(cloneListOfCourses, dictSoFar)
+ var result = recursiveFunction(cloneListOfCourses, {...dictSoFar})

Basic Javascript, How can i filter an array by numeric value?

this is my first question on this community and i'm a novice programmer with JavaScript.
I have something like this:
let dog = [["extra small", 2], ["small", 5], ["medium", 7], ["big", 9], ["extra big", 12]];
Taking the data of the previous array, i want to create a new array just with the numeric values, for example:
ages = [2, 5, 7, 9, 12]
I tried to use "filter", but i don't know how to properly use it, also i tried to search some references to make it work but i couldn't.
Thanks in advance (and sorry for my poor english, but i suppose you get the idea).
You can first use Array#map to get just the numbers and then Array#sort to sort the numbers
let dog = [
["extra small", 2],
["small", 5],
["medium", 7],
["big", 9],
["extra big", 12]
];
let ages = dog.map(([size, age]) => age).sort((a, b) => a - b);
console.log(ages);
Here are my thoughts on how to achieve this.
Using Array#Map and Array#filter.
Basically, mapping each element of the array, then checking for the numeric values in the subArray using JavaScript#isNaN() and
returning the numbers.
isNaN() checks if the value type is not a number. !isNaN() reverses that response.
flat() is used to flatten the final result to a single array. Alternatively, you can change map() to flatMap()
// map(), isNaN(), filter(), flat()
let newArr = dog.map((arr) => arr.filter((val) => !isNaN(val))).flat();
console.log(newArr); // [ 2, 5, 7, 9, 12 ]
// flatMap(), isNaN(), filter()
let newArr = dog.flatMap((arr) => arr.filter((val) => !isNaN(val)));
console.log(newArr); // [ 2, 5, 7, 9, 12 ]
Using function.
This is similar to the first, however, instead of using map() we use a Array#forEach to loop through the array.
function getNumeric(array) {
let result = [];
array.forEach((arr) => {
let res = arr.filter((a) => !isNaN(a));
result.push(...(res));
});
return result;
}
let newArr = getNumeric(dog);
console.log(newArr); // [ 2, 5, 7, 9, 12 ]
let dog = [
["extra small", 2],
["small", 5],
["medium", 7],
["big", 9],
["extra big", 12]
];
const newArr = dog.map(item => {
return item[1]
})
console.log(newArr);

sort and filter an object array with lodash (or vanilla javascript)

I have this object I want to sort and filter by retaining only the 2 highest values by object.
obj={ A :[{
asset: 9,
biodiversity: 4,
infrastructure: 15,
deflation: 11,
energy: 9
}],
B:[{
asset: 12,
biodiversity: 10,
infrastructure: 9,
deflation: 7,
energy: 15
}],
C:[{
asset: 2,
biodiversity: 12,
infrastructure: 6,
deflation: 6,
energy: 8
}]}
I would like to sort the objects by their values and filter out the 2 highest e.g:
{A :[{
infrastructure: 15,
deflation: 11
}],
B:[{
energy: 15,
asset: 12
}],
C:[{
biodiversity: 12,
energy: 8
}]}
I have tried this for sorting:
Object.keys(obj).forEach((a) => _.sortBy(obj[a][0])))
But that is wrong obviously.
I am using lodash but will accept vanilla javascript solution as well.
You could get the entries of the inner objects and sort by value descending, get the top two key/value pairs and build a new object from it.
const
data = { A: [{ asset: 9, biodiversity: 4, infrastructure: 15, deflation: 11, energy: 9 }], B: [{ asset: 12, biodiversity: 10, infrastructure: 9, deflation: 7, nergy: 15 }], C: [{ asset: 2, biodiversity: 12, infrastructure: 6, deflation: 6, energy: 8 }]},
result = Object.fromEntries(Object
.entries(data)
.map(([k, a]) => [k, a.map(o => Object.fromEntries(Object
.entries(o)
.sort((a, b) => b[1] - a[1])
.slice(0, 2)
))])
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
(Edit/Note: This is based on the code you originally posted. I'm glad to see you updated your question and got rid of the wrapping array.)
Here's a relatively functional approach.
The secondLargestValue function finds the threshold value within each object.
The copyWithoutValsBelowThreshold function gives us a modified copy of the object.
We loop though the entries in the top-level object and apply these two functions.
See comments in the code for further clarification.
let json = getArray(); // Identifies the original array
// Defines `secondLargestVal` function
const secondLargestVal = someObj =>
// Gets second item of array after sorting numerically in descending order
Object.values(someObj).sort((a, b) => b - a)[1];
// Defines `copyWithoutValsBelowThreshold` function
const copyWithoutValsBelowThreshold = ( (someObj, threshold) => {
// This function doesn't mutate the original value
clone = Object.assign({}, someObj); // Copies obj
for(let prop in clone){
// Loops through properties, deleting non-qualifying ones
if(clone[prop] < threshold){
delete clone[prop];
}
}
return clone;
});
// Defines our main function
const mutateJson = () => {
let entries = Object.entries(json[0]);
entries = entries.map(entry => {
// `entry[0]` is the property name (eg: 'A') -- we don't actually use this
// `entry[1]` is the value (in this case, an array containing a single object)
let obj = entry[1][0]; // Identifies the actual object
const threshold = secondLargestVal(obj); // Identifies minimum value
// Updates the entry, deleting properties whose values are too low
entry[1][0] = copyWithoutValsBelowThreshold(obj, threshold);
return entry;
});
json[0] = Object.fromEntries(entries); // Replaces the top-level object
}
// Calls the main function
mutateJson();
console.log(json);
// Provides the original array
function getArray(){
return [{ A :[{
asset: 9,
biodiversity: 4,
infrastructure: 15,
deflation: 11,
energy: 9
}],
B:[{
asset: 12,
biodiversity: 10,
infrastructure: 9,
deflation: 7,
energy: 15
}],
C:[{
asset: 2,
biodiversity: 12,
infrastructure: 6,
deflation: 6,
energy: 8
}]}]
}

How to sort just a specific part of an already sorted 2D Array depending on new values. But only if the first sorted values match in Javascript

I have the following problem:
I have an array with objects in it.
Every object has a score and a rank, like this:
[
{ "score": 20, "rank": 12 },
{ "score": 20, "rank": 7 },
{ "score": 34, "rank": 4 }
]
First of all, I sort this descending by the score and store it into a 2-dimensional array.
[34, 4]
[20, 12]
[20, 7]
But now, if there is the same score twice or more often I want those to be sorted by the rank. So whatever has the lowest rank will have a smaller index number. Resulting in:
[34, 4]
[20, 7]
[20, 12]
I really don't know how to do this, I made some approaches, but they are a way to bad to mention them.
You can check if the difference of score of two objects is 0 then return the difference of rank otherwise return difference of score
const arr = [
{ "score": 20, "rank": 12 },
{ "score": 20, "rank": 7 },
{ "score": 34, "rank": 4 }
]
let res = [...arr]
.sort((a,b) => (b.score - a.score) || (a.rank - b.rank))
.map(x => [x.score,x.rank]);
console.log(res)
Just use lodash and orderby 2 fields.
You could sort the array first and then just map over for the Object.values:
const arr = [
{ "score": 20, "rank": 12 },
{ "score": 20, "rank": 7 },
{ "score": 34, "rank": 4 }
]
let result = arr.sort((a,b) => (b.score - a.score) || (a.rank - b.rank))
.map(x => Object.values(x))
console.log(result)

How can I get the largest number value along with the username from this array?

Im trying to get the user & value with the highest number from this array but have had no luck in my searches. I'm starting to wonder if my array is poorly written.
{
"radtech2": 1,
"conorlarkin4": 25,
"jdon2001": 15,
"nobel_veo": 101,
"frapoden": 1,
"duckyboy17": 31,
"faeded": 30,
"jimbob20001": 17,
"leb0wski": 15,
"3cavalry": 2,
"hardoak22": 25,
"deep_slide": 10000,
"sillywil": 7
}
const users = {
"radtech2": 1,
"conorlarkin4": 25,
"jdon2001": 15,
"nobel_veo": 101,
"frapoden": 1,
"duckyboy17": 31,
"faeded": 30,
"jimbob20001": 17,
"leb0wski": 15,
"3cavalry": 2,
"hardoak22": 25,
"deep_slide": 10000,
"sillywil": 7
};
const highestUser = users => Object.keys(users).reduce(
(highest, current) => highest.val > users[current] ? highest : { user: current, val: users[current] },
{ user: undefined, val: -Infinity }
).user;
console.log(highestUser(users));
Use keys() and entries() methods to search your JSON object. Save largest value into e.g. const largest and then find out which key belongs to this value.
Let me try to squeeze it into a one-liner approach using Object.keys() and Array.reduce().
const users = {
"radtech2": 1,
"conorlarkin4": 25,
"jdon2001": 15,
"nobel_veo": 101,
"frapoden": 1,
"duckyboy17": 31,
"faeded": 30,
"jimbob20001": 17,
"leb0wski": 15,
"3cavalry": 2,
"hardoak22": 25,
"deep_slide": 10000,
"sillywil": 7
};
const res = Object.keys(users).reduce((a, b) => users[a] > users[b] ? a : b);
console.log(res);
How the above code works is that I get the array of keys from the users object, and I use reduce to get the highest possible value and return the corresponding property from the array obtained from Object.keys().
What you show in your question is an Object, not an Array; however, it does need to be turned into an array in order to work with it.
You can do that with Object.entries(), which will return an array of all the key/value pairs in the object.
Then you can use Array.reduce() to extract the one with the largest value.
const data = {
"radtech2": 1,
"conorlarkin4": 25,
"jdon2001": 15,
"nobel_veo": 101,
"frapoden": 1,
"duckyboy17": 31,
"faeded": 30,
"jimbob20001": 17,
"leb0wski": 15,
"3cavalry": 2,
"hardoak22": 25,
"deep_slide": 10000,
"sillywil": 7
}
let winner = Object.entries(data).reduce((a, b) => (a[1] > b[1]) ? a : b)
console.log(winner)

Categories