kth largest element(string) in an array based on length - javascript

I need to find the kth largest element in an array(of strings) and return them according to the rank.
Example -
Input
var array = ['java','python','javascript','C','Swift','Dart'];
Expected Output
[['javascript', 1],
['python', 2],
['Swift', 3],
['java', 4],
['Dart', 4],
['C', 5]]
I tried this -
var rank = 0
var result = []
var arr = ['java','python','javascript','C','Swift','Dart'];
arr.sort((a,b)=>b.length-a.length);
for(let i=0;i<arr.length;i++){
if(arr[i+1]===undefined){
break;
}
else if (arr[i].length>arr[i+1].length){
++rank}
result.push([arr[i],rank])
}
console.log(JSON.stringify(result))
But as you can see, it dint work. How do I approach this? A little help, please.

const arr = ['java','python','javascript','C','Swift','Dart'];
arr.sort((a, b) => b.length - a.length)
const res = arr.reduce((acc, el) => {acc.push([el, acc.length == 0 ? 1 : el.length == acc[acc.length-1][0].length ? acc[acc.length-1][1] : acc[acc.length-1][1]+1]); return acc}, [])
console.log(JSON.stringify(res))
If you want to do it your way, you can do something like the following:
let rank = 1
const arr = ['java','python','javascript','C','Swift','Dart'];
arr.sort((a,b)=>b.length-a.length);
const result = [[arr[0], 1]]
for(let i=1;i<arr.length;i++){
if (arr[i].length<arr[i-1].length){
++rank}
result.push([arr[i],rank])
}
console.log(JSON.stringify(result))

You could make use of the fact that object properties are iterated in order of index value:
const array = ['java','python','javascript','C','Swift','Dart'];
const buckets = Object.fromEntries(array.map(a => [a.length, []]));
for (let word of array) buckets[word.length].push(word);
const result = Object.values(buckets)
.reverse()
.map((bucket, rank) => bucket.map(word => [rank+1, word]))
.flat();
console.log(result);

Related

Check if an array contains all of the elements of another array

So I'm making a program that has 2 arrays: Array1: the input form the user, and Array2: an array that the program needs to check. If Array2 has includes all of the elements of Array1, then de program does something.
Oh and I'm making it in html javascript, and not node.js
if(Array1 != ""){
for(i =0; i < Array2.length; i++){
var currentelem = Array2[i].split("+");
for(j=0; j < currentelem.length; j++){
if(Array1.includes(currentelem[j])){
alert("asd")
}
}
}
}
You can combine the .every() and .includes()
methods:
let array1 = [1,2,3],
array2 = [1,2,3,4],
array3 = [1,2];
let checker = (arr, target) => target.every(v => arr.includes(v));
console.log(checker(array2, array1)); // true
console.log(checker(array3, array1)); // false
Oh and this was not Original, all the credit goes to user Mohammad Usman you can check him out on https://stackoverflow.com/users/5933656/mohammad-usman
You could take an object and count the items and return false if some item has some count.
const
check = (a, b) => {
const
count = (c, i) => v => c[v] = (c[v] || 0) + i,
counts = {};
a.forEach(count(counts, 1));
b.forEach(count(counts, -1));
return !Object.values(counts).some(Boolean);
};
console.log(check([], [1]));
console.log(check([1], []));
console.log(check([1], [1]));
console.log(check([1, 1], [1]));
console.log(check([1, 1], [1, 1]));
function arrayContains(x,y) {
// returns true if array x contains all elements in array y
return !x.reduce((y,e,t)=>
(t=y.indexOf(e),t>=0&&y.splice(t,1),y),[...y]).length
}
console.log(arrayContains([1,2,3,4,4],[1,2,4,4]))
console.log(arrayContains([1,2,3,4], [1,2,4,4]))
console.log(arrayContains([1,2,3,4,4],[1,2,4,4,5]))

How to remove repeated number from an array?

How to completely remove repeated numbers from an array?
For example, if:
const array = [1, 1, 2, 3, 1, 2, 5]
The output should be:
[3, 5]
You could take an object for keeping track of seen items, by taking an array with the value or set the arrays value to zero.
Finally flat the result set to remove empty arrays.
const
array = [1, 1, 2, 3, 1, 2, 5],
result = array
.reduce((o => (r, v) => {
if (v in o) o[v].length = 0;
else r.push(o[v] = [v]);
return r;
})({}), [])
.flat();
console.log(result);
Roko and Ke1vans had answered in functional approaches. Both of them are correct. However, I'd show an answer in imperative approach, which may seems easier for new comer.
Similar to their flow. First, we count the occurrence of each number. Then we select the numbers that has occurred once (hence being non-repeated) into the output array.
let array = [1,1,2,3,1,2,5]
let counts = {}
let output = []
// loop each elements in the array as `item`
for(let item of array) {
// If the item is not set in the counts, `counts[item]` will be `undefined`.
// Using `|| 0` means use zero as fallback value if the items is unseen.
let count = counts[item] || 0
counts[item] = count + 1
}
// loop each keys in the object (key-value pairs) as `item`
for(let item in counts) {
let count = counts[item]
if(count == 1) {
// `+item` converts the key from string into number
output.push(+item)
}
}
console.log(output) // will print out `[ 3, 5 ]`
You can iterate and create a map of values. later iterate and filter.
const data = [1, 1, 2, 3, 1, 2, 5];
const findUniques = (data = []) => {
const map = data.reduce((m, num) => {
m[num] = (m[num] || 0) + 1;
return m;
}, {});
return data.filter((num) => map[num] === 1);
};
console.log(findUniques(data));
You can also do the same using 2 set, or 2 array.
const data = [1, 1, 2, 3, 1, 2, 5];
const findUniques2 = (data = []) => {
let unique = new Set();
let seen = new Set();
for (let num of data) {
if (seen.has(num)) unique.delete(num);
else unique.add(num);
seen.add(num);
}
return Array.from(unique);
};
console.log(findUniques2(data));
Use an Object where the key is the number, and the value is the number of occurrences. Than reduce it back to the desired array of values:
const arr = [1,1,2,3,1,2,5];
const res = Object.entries(arr.reduce((ob, v) => {
if (!(v in ob)) ob[v] = 0;
ob[v] += 1; // Count occurrences
return ob;
}, {})).reduce((arr, [k, v]) => { // Reduce back to Array
if (v === 1) arr.push(+k); // Only keys with 1 occurrence
return arr;
}, []);
console.log(res); // [3, 5]
You can use Array.filter() (Array filter article) for this for Example :
const a = [ 1 , 1 , 2 , 3 , 2 , 4 , 5 , 7];
function filter(value , index , array){
// looping through all the objects in the array
for(let i=0; i<array.length; i++) {
if(i != index && array[i] == value) return false; // return 'false' if the value has a duplicate other than itself
}
// return 'TRUE' if value hasn't been duplicated
return true;
}
const b = a.filter(filter); // [3, 4, 5, 7]
And the short version if this function's going to be used only once:
const a = [ 1 , 1 , 2 , 3 , 2 , 4 , 5 , 7];
const b = a.filter((value , index , array) => {
for(let i=0; i<array.length; i++) if(i != index && array[i] == value) return false;
return true;
});
// [3, 4, 5, 7]
You could find duplicates and then operate a difference.
let a = [1,1,2,3,1,2,5];
const findDuplicates = (nums) => {
nums.sort(); // alters original array
let ans = []
for(let i = 0; i< nums.length; i++){
if(nums[i] === nums[i+1]){
if(ans[ans.length -1] !== nums[i]){
ans.push(nums[i])
}
}
}
return ans;
}
duplicates = new Set(findDuplicates(a))
let difference = new Set([...a].filter(x => !duplicates.has(x)))
console.log(Array.from(difference))
output : [ 3, 5 ]
Note : I grab the findDuplicates function from this link
const data = [1, 1, 2, 3, 1, 2, 5];
const s = new Set();
const res = data.filter((a, i) => {
if (data.lastIndexOf(a) > i || s.has(a)) {
s.add(a);
return false;
}
return true;
});
console.log(res); //=> [3, 5]

How to change elements of array without loop

I would like to change all elements of array (for example arr[i] +=1), but I want to do it more efficiently, without for-loop.
My for-loop implementation:
let arr = [1,2,3,4,5]
for (let i = 0; i < arr.length; i++) {
arr[i] += 1
}
console.log(arr)
// arr = [2, 3, 4, 5, 6]
In ESX using map() or reduce() methods.
Your math function:
const mathFunction = (a) => ++a
map() method
arr = arr.map(it => mathFunction(it))
reduce() method
arr = arr.reduce((acc, rec) => acc.concat(mathFunction(rec)), [])
You can use map()
let arr = [1,2,3,4,5]
arr = arr.map(x => x + 1);
console.log(arr)
Or use this:
const arrElementsPlusOne = arr.reduce((acc, nmb) => [ ...acc, nmb + 1 ], []);
You will get immutable array.

Is there a simpler way to create a sum of previous values in an array?

I'm basically looking for a simpler way to do this:
heights.forEach((height, i) => {
var p = i > 0 ? i -1 : 0;
this.breakingPoints.push(height+heights[p])
})
If I input an array that is:
[0,2,5,5]
I would like to output
[0,2,7,12]
You could use map() method with closure to return new array.
const arr = [0,2,5,5];
const result = (s => arr.map(e => s += e))(0);
console.log(result)
You can simply store the variable to push in a variable which will allow you to automatically sum the new value to it without checking the index.
var total = 0;
heights.forEach(height => {
this.breakingPoints.push(total += height);
})
The result would be:
[0, 2, 7, 12]
You can use Array.reduce method.
let inputArray = [1, 2, 3, 4];
let outputArray = [];
inputArray.reduce(function(accumulator, currentValue, currentIndex) {
return outputArray[currentIndex] = accumulator + currentValue; }, 0);
You could use reduce and spread operator to concat values:
const input = [0, 2, 5, 5];
const output = input.reduce((acc, val) => [...acc, (acc[acc.length - 1] ? acc[acc.length - 1] : 0) + val],[]);
Or when using < ES6
var output = input.reduce(function (acc, val) { return acc.concat([(acc[acc.length - 1] ? acc[acc.length - 1] : 0) + val]); }, []);

How to calculate intersection of multiple arrays in JavaScript? And what does [equals: function] mean?

I am aware of this question, simplest code for array intersection but all the solutions presume the number of arrays is two, which cannot be certain in my case.
I have divs on a page with data that contains arrays. I want to find the values common to all arrays. I do not know how many divs/arrays I will have in advance. What is the best way to calculate values common to all arrays?
var array1 = ["Lorem", "ipsum", "dolor"];
var array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
var array3 = ["Jumps", "Over", "Lazy", "Lorem"];
var array4 = [1337, 420, 666, "Lorem"];
//Result should be ["Lorem"];
I found another solution elsewhere, using Underscore.js.
var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
_.intersection.apply(_, arrayOfArrays)
//Result is [43]
I've tested this with simple dummy data at my end and it seems to work. But for some reason, some of the arrays I'm producing, which contain simple strings, also automatically include an added value, "equals: function":
["Dummy1", "Dummy2", "Dummy3", equals: function]
And whenever I use the Underscore.js intersection method, on an array of arrays, I always get [equals: function] in dev tools, and not - if "Dummy3" is common to all arrays - ["Dummy3"].
So TL;DR is there another solution to array intersection that would suit my case? And can anyone explain what [equals: function] means here? When I expand the item in the dev tools, it produces an empty array and a list of methods available on arrays (pop, push, shift etc), but these methods are all faded out, while equals: function is highlighted.
You could just use Array#reduce with Array#filter and Array#includes.
var array1 = ["Lorem", "ipsum", "dolor"],
array2 = ["Lorem", "ipsum", "quick", "brown", "foo"],
array3 = ["Jumps", "Over", "Lazy", "Lorem"],
array4 = [1337, 420, 666, "Lorem"],
data = [array1, array2, array3, array4],
result = data.reduce((a, b) => a.filter(c => b.includes(c)));
console.log(result);
I wrote a helper function for this:
function intersection() {
var result = [];
var lists;
if(arguments.length === 1) {
lists = arguments[0];
} else {
lists = arguments;
}
for(var i = 0; i < lists.length; i++) {
var currentList = lists[i];
for(var y = 0; y < currentList.length; y++) {
var currentValue = currentList[y];
if(result.indexOf(currentValue) === -1) {
var existsInAll = true;
for(var x = 0; x < lists.length; x++) {
if(lists[x].indexOf(currentValue) === -1) {
existsInAll = false;
break;
}
}
if(existsInAll) {
result.push(currentValue);
}
}
}
}
return result;
}
Use it like this:
intersection(array1, array2, array3, array4); //["Lorem"]
Or like this:
intersection([array1, array2, array3, array4]); //["Lorem"]
Full code here
UPDATE 1
A slightly smaller implementation here using filter
This can be done pretty succinctly if you fancy employing some recursion and the new ES2015 syntax:
const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];
const arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
// Filter xs where, for a given x, there exists some y in ys where y === x.
const intersect2 = (xs,ys) => xs.filter(x => ys.some(y => y === x));
// When there is only one array left, return it (the termination condition
// of the recursion). Otherwise first find the intersection of the first
// two arrays (intersect2), then repeat the whole process for that result
// combined with the remaining arrays (intersect). Thus the number of arrays
// passed as arguments to intersect is reduced by one each time, until
// there is only one array remaining.
const intersect = (xs,ys,...rest) => ys === undefined ? xs : intersect(intersect2(xs,ys),...rest);
console.log(intersect(array1, array2, array3, array4));
console.log(intersect(...arrayOfArrays));
// Alternatively, in old money,
var intersect2ES5 = function (xs, ys) {
return xs.filter(function (x) {
return ys.some(function (y) {
return y === x;
});
});
};
// Changed slightly from above, to take a single array of arrays,
// which matches the underscore.js approach in the Q., and is better anyhow.
var intersectES5 = function (zss) {
var xs = zss[0];
var ys = zss[1];
var rest = zss.slice(2);
if (ys === undefined) {
return xs;
}
return intersectES5([intersect2ES5(xs, ys)].concat(rest));
};
console.log(intersectES5([array1, array2, array3, array4]));
console.log(intersectES5(arrayOfArrays));
Using a combination of ideas from several contributors and the latest ES6 goodness, I arrived at
const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];
Array.prototype.intersect = function intersect(a, ...b) {
const c = function (a, b) {
b = new Set(b);
return a.filter((a) => b.has(a));
};
return undefined === a ? this : intersect.call(c(this, a), ...b);
};
console.log(array1.intersect(array2, array3, array4));
// ["Lorem"]
For anyone confused by this in the future,
_.intersection.apply(_, arrayOfArrays)
Is in fact the most elegant way to do this. But:
var arrayOfArrays = [[43, 34343, 23232], [43, 314159, 343], [43, 243]];
arrayOfArrays = _.intersection.apply(_, arrayOfArrays);
Will not work! Must do
var differentVariableName = _.intersection.apply(_,arrayOfArrays);
The cleanest way I've found to do this wasn't actually listed on this page, so here you are:
arrays[0].filter(elem => arrays.every(array => array.includes(elem)))
Reads like nice, clear english: every array includes the element. It assumes that you have at least 1 element in arrays, though. If you can't make this assumption, you can use optional chaining:
arrays?[0].filter(elem => arrays.every(array => array.includes(elem))) ?? []
Your code with _lodash is working fine.
As you can say in this fiddle:
this code:
var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
var a = _.intersection.apply(_, arrayOfArrays);
console.log(a);
console.log(a.length);
Will have output:
[42]
1
Maybe you see
equals: function
because you are using kind of debugger.
Try to just print the array with console.log, you will get only 42.
Small recursive divide and conquer solution that does not rely on es6 or any library.
It accepts an array of arrays which makes the code shorter and allows you to pass arguments by using map.
function intersection(a) {
if (a.length > 2)
return intersection([intersection(a.slice(0, a.length / 2)), intersection(a.slice(a.length / 2))]);
if (a.length == 1)
return a[0];
return a[0].filter(function(item) {
return a[1].indexOf(item) !== -1;
});
}
var list1 = [ 'a', 'b', 'c' ];
var list2 = [ 'd', 'b', 'e' ];
var list3 = [ 'f', 'b', 'e' ];
console.log(intersection([list1, list2, list3]));
If you can use ES6 Maps and your arrays items are scalar values (easily usable as Map keys), then you can try this (works in my case) :
const intersect_lists = (lists) => {
const results = []
const lookup = new Map()
lists.map((list, idx) => {
list.map((element) => {
const count = lookup.get(element) || 0
if(count === idx) {
lookup.set(element, 1 + count)
} else {
lookup.delete(element)
}
})
})
// only elements present in all lists will have
// their respective counter equllling the total number of lists
Array.from(lookup.keys()).map((key) => {
if(lookup.get(key) === lists.length) {
results.push(key)
}
})
return results
}
Optionally you can pre-sort "lists" (of lists) by creasing length to avoid lots of iterations of the outer map() call, especially if lists lengths are heterogenous :
lists.sort((l1, l2) => l1.length - l2.length).map((list, idx) => { ... })
Sol with Maps
// nums1 = [1,2,2,1], nums2 = [2,2]
// n m
// O(nm) + space O(min(n, m))
// preprocess nums2 to a Map<number, count>
// O(n + m) + space(min(n, m))
// process the shorter one
let preprocessTarget = nums1
let loopTarget = nums2
if (nums1.length > nums2.length) {
preprocessTarget = nums2
loopTarget = nums1
}
// Map<element, number>
const countMap = new Map()
for (let num of preprocessTarget) {
if (countMap.has(num)) {
countMap.set(num, countMap.get(num) + 1)
} else {
countMap.set(num, 1)
}
}
const result = []
for (let num of loopTarget) {
if (countMap.has(num)) {
result.push(num)
const count = countMap.get(num)
if (count === 1) {
countMap.delete(num)
} else {
countMap.set(num, count - 1)
}
}
}
return result
const data = [array1, array2, array3, array4].filter(arr => arr.length > 0);
const result = [...new Set(data)];
let final = Array.of<any>();
for (const key of result) {
final = final.concat(key);
}
console.log(final);
Lodash pure:
_.keys(_.pickBy(_.groupBy(_.flatten(arrays)), function (e) {return e.length > 1}))
Lodash with plain js:
var elements = {}, duplicates = {};
_.each(arrays, function (array) {
_.each(array, function (element) {
if (!elements[element]) {
elements[element] = true;
} else {
duplicates[element] = true;
}
});
});
_.keys(duplicates);
I manage to accomplish this with a reduce call:
var intersected = intersect([[1, 2, 3], [2, 3, 4], [3, 4, 5]]);
console.log(intersected); // [3]
function intersect(arrays) {
if (0 === arrays.length) {
return [];
}
return arrays.reduce((intersection, array) => {
return intersection.filter(intersectedItem => array.some(item => intersectedItem === item));
}, arrays[0]);
}
Intersection of a variable number of arrays.
This is how I do it:
function getArraysIntersection(list1, list2, ...otherLists) {
const result = [];
for (let i = 0; i < list1.length; i++) {
let item1 = list1[i];
let found = false;
for (var j = 0; j < list2.length && !found; j++) {
found = item1 === list2[j];
}
if (found === true) {
result.push(item1);
}
}
if (otherLists.length) {
return getArraysIntersection(result, otherLists.shift(), ...otherLists);
}
else {
return result;
}
}
SNIPPET
function getArraysIntersection(list1, list2, ...otherLists) {
const result = [];
for (let i = 0; i < list1.length; i++) {
let item1 = list1[i];
let found = false;
for (var j = 0; j < list2.length && !found; j++) {
found = item1 === list2[j];
}
if (found === true) {
result.push(item1);
}
}
if (otherLists.length) {
return getArraysIntersection(result, otherLists.shift(), ...otherLists);
}
else {
return result;
}
}
const a = {label: "a", value: "value_A"};
const b = {label: "b", value: "value_B"};
const c = {label: "c", value: "value_C"};
const d = {label: "d", value: "value_D"};
const e = {label: "e", value: "value_E"};
const arr1 = [a,b,c];
const arr2 = [a,b,c];
const arr3 = [c];
const t0 = performance.now();
const intersection = getArraysIntersection(arr1,arr2,arr3);
const t1 = performance.now();
console.log('This took t1-t0: ' + (t1-t0).toFixed(2) + ' ms');
console.log(intersection);
const intersect = (arrayA, arrayB) => {
return arrayA.filter(elem => arrayB.includes(elem));
};
const intersectAll = (...arrays) => {
if (!Array.isArray(arrays) || arrays.length === 0) return [];
if (arrays.length === 1) return arrays[0];
return intersectAll(intersect(arrays[0], arrays[1]), ...arrays.slice(2));
};
For anyone who might need, this implements the intersection inside an array of arrays:
intersection(array) {
if (array.length === 1)
return array[0];
else {
array[1] = array[0].filter(value => array[1].includes(value));
array.shift();
return intersection(array);
}
}
function getIntersection(ar1,ar2,...arrays){
if(!ar2) return ar1
let intersection = ar1.filter(value => ar2.includes(value));
if(arrays.length ===0 ) return intersection
return getIntersection(intersection,...arrays)
}
console.log(getIntersection([1,2,3], [3,4], [5,6,3]) // [3]
Function to calculate intersection of multiple arrays in JavaScript
Write a method that creates an array of unique values that are included in all given arrays. Expected Result: ([1, 2], [2, 3]) => [2]
const arr1 = [1, 2, 1, 2, 1, 2];
const arr2 = [2, 3];
const arr3 = ["a", "b"];
const arr4 = ["b", "c"];
const arr5 = ["b", "e", "c"];
const arr6 = ["b", "b", "e"];
const arr7 = ["b", "c", "e"];
const arr8 = ["b", "e", "c"];
const intersection = (...arrays) => {
(data = [...arrays]),
(result = data.reduce((a, b) => a.filter((c) => b.includes(c))));
return [...new Set(result)];
};
console.log(intersection(arr1, arr2)); // [2]
console.log(intersection(arr3, arr4, arr5)); // ['b']
console.log(intersection(arr5, arr6, arr7, arr8)); // ['b', 'e']

Categories