How to rank array elements? - javascript

I tried searching using many different keywords but I'm unable to get the result I'm looking for.
I've created a table with five values as such: 10, 3, 5, 4, 2
I have a row on top of the table which shows the rank.
So, above 10, it should say "5"
Above 3, it should say "2"
Above 5, it should say "4"
Above 4, it should say "3"
Above 2, it should say "1"
I can take care of the tabular column. It is the main script that I don't understand.
I thought I can create a duplicate array of the original one and sort the duplicate - Then compare both original and duplicate to rank them. It turns out that when I sort the duplicate array, the original is also sorted.
I thought I can create 2 duplicate arrays and not touch the original one. It still sorts all of the arrays. How can I do this then?

It sounds like you are looking for how to clone or deep copy an array. When you do something like:
var a = [5,4,3,2,1]
var b = a;
Array b is set to refer to array a. If you, however, take a slice or do something else to get a copy of the data (not something refering to the actual structure), you can clone the array. So something like:
var a = [5,4,3,2,1]
var b = a.slice(0);
will give you an array b that won't change if you change a. See articles like this for more information.

You can duplicate the array using spread. From there you can do a simple sort() to get the rank you're trying to achieve:
const arr = [10, 3, 5, 4, 2];
const sortedArr = [...arr].sort((a,b) => a > b);
console.log(sortedArr);

Related

Understanding indexOf and lastIndexOf

I'am doing some JavaScript exercises and I stumbled upon this one "Write a JavaScript program to filter out the non-unique values in an array."
I tried and found a solution, which worked but it was to cumbersome. A better answer, according to the site, is the following:
const filter_Non_Unique = arr =>
arr.filter(l => arr.indexOf(l) === arr.lastIndexOf(l));
console.log(filter_Non_Unique([1,2,3,4,4,5,6,6])) // 1,2,3,5
Now I recked my head trying to understand why this solution works but I still don't get it.
Can somebody explain to me?
Thanks in advance.
If the element only occurs once in the array, the first index will be the same as the last index, the index will not change for both calls.
eg:
const arr = [1,2,3,4,4,5,6,6]
console.log(arr.indexOf(5))
console.log(arr.lastIndexOf(5))
Since both of of these functions return the same index, filter will keep the element in.
On the other hand if there are multiple values, those values will have different indexes, so the filter will return false, and remove it from the array:
const arr = [1,2,3,4,4,5,6,6]
console.log(arr.indexOf(4))
console.log(arr.lastIndexOf(4))
I've answered a question similar to the one you solved here, you could try that logic too.
Beside of the indexOf/lastIndexOf approach which needs a lot of iterating the array, you could take a two loop approach.
By getting an array of single items by using a hash table and three states, like
undefined, the standard value of not declared properties of an object,
true for the first found value,
false for all values who are repeated in the array.
Then filter by the value of the hash table.
const
filterNonUnique = array => {
var hash = {};
for (let v of array) hash[v] = hash[v] === undefined;
return array.filter(v => hash[v]);
}
console.log(filterNonUnique([1, 2, 3, 4, 4, 5, 6, 6, 7, 7, 7, 7]))

Clone array of objects into itself

This is my source array (e.g. with 20 elements):
var myArray= $('.my-selector').clone().toArray();
I want to clone the whole array into itself. The new array should have 40 elements (each element is existing "twice"). Like this:
myNewArray = myArray.concat($('.my-selector').clone().toArray())
But it seems that the new arrays elements are references to the original and no real clones.
Updated answer.
#JKB, I have updated my answer based on your recent comment on my old answer. I think the code you have posted in your question is actually working fine. I am using 3 elements to demo this, instead of the original 20, but the same logic applies.
I have quoted you in code comments in the code snippets, from your original question, as well as your recent comment on my old answer. Please read through them.
// "The source are jQuery objects" ~ JKB
var source = $('.my-selector')
/* "This source should be cloned into an array" - JKB
I am Copying this from your original code. */
var myArray = $('.my-selector').clone().toArray()
/* "Now i want to increase the arrays size by copying its content into itself, after that the array should contain 20 objects (each object twice)" - JKB
Our array should contain 6, since we're cloning 3 elements onto itself. Copying this again from your original code. */
var myNewArray = myArray.concat($('.my-selector').clone().toArray())
// "BUT: Now this objects should be inserted back into another DOM place (not into their original place)." - JKB
$('#anotherPlace').append(myNewArray)
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<div class="my-selector">first</div>
<div class="my-selector">second</div>
<div class="my-selector">third</div>
<div id="anotherPlace" style="background:red"></div>
But it seems that the new arrays elements are references to the
original and no real clones.
They aren't, that's why we see 2 copies of each - first, second and third in the red background div. Is this what you were looking for, or did I miss something obvious?
You can use the concat method on javascript from mdn.
The concat() method is used to merge two or more arrays. This method
does not change the existing arrays, but instead returns a new array.
var arr = ["test1", "test2", "test3"];
arr = arr.concat(arr);
hope this helps
using ES6 spread operator you can do:
const arr = [1, 2, 3]
const doubledArr = [...arr, ...arr]
console.log(doubledArr) // [1, 2, 3, 1, 2, 3]
I assume you want the objects to be cloned sequentially, so you could just concatenate the array with a clone of itself using:
arr = arr.concat(arr)

JS Splice Array of Nulls Removes Last Index Regardless of Parameters

For a reason specific to this application an array of data or nulls is used to display a list of forms. The difference is based on whether data was provided by a service or manually added, where null indicates everything was manually added via
a button not a service.
So ignoring the use case of an array of nulls it turns out that [null, null, null].splice(0, 1); removes the null at index 2 instead of 0 based on entering values into the different forms displayed based on the array length, and then seeing who disappears on delete.
It can be made to work by adding something unique like { index: theIndex } to the array instead of null. So splice now works correctly removing the item at index 0 instead of 2, but now I'm curious what splice does under the covers that it can't remove an index regardless of its value compared to the other indices.
Can anyone explain what splice is doing? Based on the spec for splice I don't really see why this happens.
(This follows from the comments in the question but is too large to be a comment).
So I think you are having a conceptual misconception (^^). Look at this examples:
let a = [1, 2, 3]
a.splice(0, 1) // => 1
a // => [2, 3]
let b = [1, 2, 3]
delete b[0] // => true
b // => [<1 empty slot>, 2, 3]
The splice function modifies the array in-place. Note that, although we spliced the first element, we got as a result an array of two elements.
Look now at this example
let a = [1, 1, 1]
a.splice(0, 1)
a // => [1, 1]
let b = [1, 1, 1]
b.splice(2, 1)
b // => [1, 1]
We are deleting the first element from a and the last from b, but of course there's no way of telling so just looking at the result.
In the case with the nulls, the same thing is happening. Some library (Angular) is trying to figure out which element you deleted, but there's no way of knowing. This is because null === null.
Now if you use an array of empty objects, for example, there would be a way of knowing. Since {} !== {}---because each time you cast a {} you are creating a unique object---, then you could know which element is missing in an array of empty objects. The case is similar with the array [1, 2, 3].
let a = [{}, {}, {}] // lets imagine that each object has a unique id
// and we have [{}#1, {}#2, {}#3]
let [obj1, obj2, obj3] = a
obj1 === obj2 // => false, because they have different ids.
a.splice(0, 1)
a // => [{}#2, {}#3]
a.includes(obj1) // => false, because {}#1 is no longer in a
So an alternative to using an array of nulls, would be to use an array of empty objects. I think that is why the code works for you when you use objects like { index: theIndex }. But of course all depends on how smart Angular is. I bet there is a more native way of deleting an element, as #KaiserKatze points out, "it's always a bad idea to directly remove or add elements in the array if it maps to your model."
You have to understand that when you are splicing the array you're only doing that--removing an element from an array. You're not removing the "form element" when splicing the array. Instead, some foreign code is reading the array and trying to figure out --under the hood-- what you intended to do.

Get what's in one array and not the other, in javascript

I have two arrays, sample1 and sample2. How can I get what's in sample1, but not sample2?
var sample1 = [1, 2, 3, 4];
var sample2 = [1, 2];
var sample3 = [3, 4]; //what I want to get
Application of this: two arrays, each containing some discord.js guildmembers.
What I've tried:
console.log(sample1.find(el => !sample2.includes(el)).toString());
// Cannot read property 'toString' of undefined
I understand a way to do this is to look through the sample1 array, and then if something is not in sample2, push it to a new array. However, I understand there are shorter and more efficient ways of doing this, especially if sample1 and sample2 were quite long.
For clarification, sample1 and sample2 are not undefined.
.find() Will return the first element that matches the condition.
What you are looking for is getting back a new array. For that you can use .filter() which returns a filtered array like so:
console.log(sample1.filter(el => !sample2.includes(el))); // outputs [3, 4]

How to efficiently search specific values in array using JavaScript

Im wondering how to search big arrays using JavaScript.
Let's say we have an array consisting of elements that represent businesses. There are a couple thousand elements in the array, they are objects that sometimes also have arrays in them.
In each of those elements is a key e.g. called category that looks like this category: ["attr1", "attr2", "attr3"]. Now I only want to find elements of the array that have a category like this:
category: ["Restaurant"]
The problem is that other keys of the elements in the array sometimes also have a property where "Restaurant" is in the name followed by something else e.g. "RestaurantPrice" so
if(array[i].categories != null &&
array[i].categories.indexOf("Restaurant") != -1) {
do something
}
Would not work properly because it would return all occurences of the word "Restaurant" or am I wrong?
If not how should I search for specific things in an array?
If categories is an array like ["foobar", "foo"]
categories.indexOf("foo") would return 1, foobar would be ignored.
The other question was how to find elements efficient?.
It depends, if your set is static, you can prebuilt and cache some sort of index like:
var categoriesMap = {
foobar: [1, 2, 4],
foo: [1, 5, 7]
}
The array would represent the indexes of items, which includes the given categories.
Try using HashMaps if your keys are unique.

Categories

Resources