Find position of all unique elements in array - javascript

let arrr = [7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90,2, 88,1];
output=[0, 1, 2, 3, 4, 5, 6, 7, 8 ,10, 12 ]
I saved this code at javascript playground here.
Question: I am trying to get all the index of unique elements in array. I have tried the code below to get the unqiue array but i do not know how to extract its index to give the expected output as above.
let ar = [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 2, 1];
let unique = ar.filter((value, index) => {
return ar.indexOf(value) == index;
});
console.log(unique);

.indexOf() will always return the index of the first match. If we combine that with a Set we get the expected output:
let input = [7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90, 2, 88, 1];
const indices = input.map(el => input.indexOf(el));
const output = new Set(indices);
const output_as_array = [...output]; // if you need an actual array
console.log(output_as_array);

Use a set to record numbers that have already been seen, and add the index to an array if it has not been see.
function uniqueIndices(arr) {
const seen = new Set();
const indices = [];
for (const [i, n] of arr.entries()) {
if (!seen.has(n)) {
seen.add(n);
indices.push(i);
}
}
return indices;
}
This also works well as a generator:
function *uniqueIndices(arr) {
const seen = new Set();
for (const [i, n] of arr.entries()) {
if (!seen.has(n)) {
seen.add(n);
yield i;
}
}
}
console.log([...uniqueIndices([7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90,2, 88,1])])

A simple function which iterates the list just once, storing the value and index in a Map, simply testing whether it's already there before adding a new one:
const uniqueIndices = (xs) =>
[...xs .reduce ((found, x, i) => found .has (x) ? found : found .set (x, i), new Map()) .values ()]
const arr = [7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90, 2, 88, 1]
console .log (uniqueIndices (arr))
.as-console-wrapper {max-height: 100% !important; top: 0}

Get all the unique values
Map over the uniques to use indexOf on the original array to get the indexes of the uniques
let arrr = [7, 9, 30, 40, 50, 8, 1, 2, 3, 40, 90,2, 88,1];
let unique = arrr.filter((v, i, a) => a.indexOf(v) === i);
let uniquesIndexes = unique.map(u => arrr.indexOf(u));
console.log(uniquesIndexes)
Output:
[
0,
1,
2,
3,
4,
5,
6,
7,
8,
10,
12
]

Related

Javascript - find out first element appears in sorted array as well as in another unsorted collection

I have an array of unsorted number and another array of sorted number, like
const unSortedArray = [54, 23, 55, 76, 9, 11];
const sortedArray= [1, 2, 3, 4, ...., 100]
How could I find out the first element appears in my sortedArray which should also be an element existed in my unSortedArray? In above example, should return 9 because 9 existed in unSortedArray as well as it positioned prior to other element in sortedArray
Note, I used 1, 2, 3, 4 in my above example, but my real world example was not number but is GUID, let's say we cannot apply sort method on unSortedArray then pick the first element.
I have thought about union both arrays, but how to union both while not break the sorting in sortedArray?
Here is some example
1) output should be 1, because even element 1, 2, 9 and 10 exists in both array, 1 has prior order than 2, 9, 10 in sortedArray
const unSortedArray = [54, 23, 55, 76, 9, 10, 2, 1];
const sortedArray= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
2) output should be 9, because even element 9 and 10 exists in both array, 9 has prior order than 10 in sortedArray
const unSortedArray = [54, 23, 55, 76, 10, 9];
const sortedArray= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
3) output should be '' because no element in unSortedArray appears in sorted Array
const unSortedArray = [54, 23, 55, 76, 11];
const sortedArray= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
A quick and dirty way to do it with a for loop:
const unSortedArray = [54, 23, 55, 76, 9, 11];
const sortedArray= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let firstVal;
for (i = 0; i < sortedArray.length; i++) {
if (unSortedArray.includes(sortedArray[i])) {
firstVal = sortedArray[i];
break;
}
}
console.log(firstVal);
You can create a Set from the unSortedArray and use set.has() in your predicate for sortedArray.find():
const unSortedArray = [54, 23, 55, 76, 9, 11];
const sortedArray= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const setHasValue = set => value => set.has(value);
const firstElement = sortedArray.find(setHasValue(new Set(unSortedArray)));
console.log(firstElement);
It would be a good idea to construct a look up table for unsorted array items. Such as
{ 54: true
, 23: true
, 55: true
.
.
11: true
}
This would be an O(k) task where k is the number of elements of the unsorted array. Then find the first item in the sorted array that returns true. This should be an O(n) task where n is the number of elements of the sorted array. Yielding a linear time solution.
This should do it.
function getFirst(usa,sa){
var h = usa.reduce((r,n) => (r[n] = true, r), {});
return sa.find(n => h[n]);
}
var r = getFirst([54,23,55,76,9,11], Array.from({length:100}, (_,i) => i+1));
console.log(r);

Array spread values until matches length of another array length, to allow arrays to zip together

I have two arrays a and b.
Either array can have any number of items. However their length may not match.
I need the array lengths to match so I can zip the two array together.
For example:
a = [1, 2, 3, 4]
and
b = [1, 2]
Becomes:
a = [1, 2, 3, 4]
and
b = [1, 1, 2, 2]
I need b to match the length of a or vice versa to whatever one is longer length.
As well as to spread the values of the shorter array until matches the length of the longer array.
The spread on the shorter array would only contain the values present at start.
For example:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
and
b = [1, 2]
Becomes
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
and
b = [1, 1, 1, 1, 1, 2, 2, 2, 2, 2]
Another example:
a = [21, 22, 23, 24, 25, 26, 27]
and
b = [39, 40, 41, 42]
Becomes:
a = [21, 22, 23, 24, 25, 26, 27]
and
b = [39, 39, 40, 40, 41, 41, 42]
SOLVED IT using Ramda
const a = [1, 2]
const b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
R.sort(R.gte, R.flatten(R.repeat(a, b.length / 2)))
Without relying on any libraries, this function will give you the desired result
const a = [21, 22, 23, 24, 25, 26, 27]
const b = [39, 40, 41, 42]
// a, b = longer array, shorter array
function spread(a, b) {
let result = null
if (a.length !== b.length) {
// target: array that needs to be spread
const [target, longest] = a.length > b.length ? [b, a] : [a, b]
// difference: amount target needs to be spread
const difference = longest.length - target.length
// check if elements need to be repeated more than twice
if (difference > target.length) {
result = [].concat(
...target.map((n, i) => {
if (typeof n !== 'string') {
return Array.from(n.toString().repeat(difference / 2)).map(Number)
}
return Array.from(n.repeat(difference / 2))
})
)
} else {
// repeat N elements twice until N <= difference/2
result = [].concat(
...target.map((n, i) => (i <= difference / 2 ? [n, n] : n))
)
}
// return the spread array
return result
}
// return original array if both arrays are same length
return b
}
spread(a, b) // => [ 39, 39, 40, 40, 41, 42 ] 
Pure JavaScript solution that will extend a shorter array to the length of a longer one. The stretching is done by repeating each value in the shorter array and dynamically re-calculating how many times this is needed. So with lengths 10 and 3, the shorter array will have the first item repeated three times but the rest only two times in order to fit:
longer length: 10
shorter: [ 1, 2, 3 ]
/|\ /| |\
/ | \ / | | \
result: [ 1, 1, 1, 2, 2, 3, 3 ]
function equaliseLength(a, b) {
const [shorter, longer] = [a, b].sort((x, y) => x.length - y.length);
let remaining = longer.length;
const stretchedArray = shorter.flatMap((item, index) => {
//how many we need of this element
const repeat = Math.ceil(remaining / (shorter.length - index));
//adjust the remaining
remaining -= repeat;
//generate an array with the element repeated
return Array(repeat).fill(item)
});
//return to the order of the input:
//if `a` was the longer array, it goes first
//otherwise flip them
return longer === a ?
[longer, stretchedArray] :
[stretchedArray, longer]
}
console.log(printResult(
[1, 2, 3, 4],
[1, 2]
));
console.log(printResult(
[21, 22, 23, 24, 25, 26, 27],
[39, 40, 41, 42]
));
console.log(printResult(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[1, 2]
));
console.log(printResult(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[1, 2, 3]
));
console.log(printResult(
[1, 2, 3],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
));
console.log(printResult(
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
));
//just to make the display better
function printResult(a, b) {
const [resultA, resultB] = equaliseLength(a, b)
.map(x => x.map(y => String(y).padStart(2)))
.map(x => x.join("|"))
return `a = ${JSON.stringify(a)} b = ${JSON.stringify(b)}
result:
a = |${resultA}|
b = |${resultB}|`;
}

Organize duplicates into individual array that is ordered

I have an array with numbers. I would like to put the numbers in order and create new array with duplicats in the same array(array in array). Can someone please help me step by step. I would really like to understand
let arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];
// I want to create this [[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591]
const sortArray = arr.sort(function(a, b) {
return a - b;
});
You can extract unique values using Set, then sort them (because sorting an array of arrays is more complex), then use array.reduce to acquire all the items in the original array and push either the single value if unique, otherwise the array of values (not sure why you need that, but still..)
Further documentation reference:
What is Set?
Array.reduce
Working code below:
let arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];
// I want to create this [[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591]
console.log([...new Set(arr)].sort((a,b) => a - b).reduce((accumulator, next) => {
const filtered = arr.filter(i => i === next);
return accumulator.push(filtered.length === 1 ? filtered[0] : filtered), accumulator
}, []));
You could sort the array and have a look to the last two items and the actual item.
[ 1, 1, 1, 1, 2, 2, 2, 4, 5, 10, 20, 20, 391, 392, 591] array
a b c variables
^ actual item
Then check if the last item b and the actual item c is unequal and return a new array with the the old items and the actual item.
If the item before the last item a and the actual item is unequal, it should be an array for the last item in the result set and the actual item.
Otherwise push the actual item to the nested last array of the result set.
var array = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20],
result = array
.sort((a, b) => a - b)
.reduce((r, c, i, { [i - 2]: a, [i - 1]: b }) => {
if (b !== c) return [...r, c];
if (a !== c) return r.pop(), [...r, [b, c]];
r[r.length - 1].push(c);
return r;
}, []);
console.log(result);
Although there are other approaches, whenever I need to parse unique values from an array in this way, I will create an object with the object's properties representing the groupings of array values
{ 1: [1, 1, 1], 2: [2 , 2, 2], 4: [4], 5: [5] ...}
Then you can use a native object method to get all keys or values from the object if you need to (or if your end goal is different, you can use the object however it is needed)
Object.keys(obj)
// or
Object.values(obj)
For your case, it would look like
const arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];
const obj = arr.reduce((accum, val) => {
accum[val] = accum[val] || [];
accum[val].push(val);
return accum;
}, {});
const finalArr = Object.values(obj).map(val => val.length > 1 ? val : val[0]);
console.log(finalArr);
You can count the occurrences and then use that object to create your final array.
const arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];
const count = arr.reduce((acc, val) => {
acc[val] = acc[val] + 1 || 1;
return acc;
}, {});
const result = Object
.keys(count)
.sort((a, b) => a - b)
.map((key) => count[key] === 1 ? +key : Array.from({ length: count[key] }).fill(+key));
console.log(result);
You can do this thing in ways. But if you want to achieve in best way, you must avoid n square loops.
So can create a dictionary of count of values. And loop over the keys of the object in sorted order.
Using Array.reduce to create object of count of array elemnts. and Array.fill to fil an array with same values.
//Given Array
const arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];
//Dictionary with count of each values in array
const arrCountObj = arr.reduce((acc, el) => {
if (acc[el]) {
acc[el] += 1
} else {
acc[el] = 1
}
return acc
}, {})
console.log(arrCountObj)
//Looping over sorted dictionary keys to create array based on condition
var out = Object.keys(arrCountObj).sort((a, b) => a - b).map(x => arrCountObj[x] > 1 ? new Array(arrCountObj[x]).fill(+x) : arrCountObj[x])
console.log(out)
Time Complexity: O(nlogn)
You could:
1) iterate through the array an build a frequency map of the the numbers
2) grab and sort the frequency map key in ascending order
3) build a new array from the information in the frequency map
const arr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];
const obj = arr.reduce((acc, c) => {
return acc[c] = (acc[c] || 0) + 1, acc;
}, {});
// {"1":4,"2":3,"4":1,"5":1,"10":1,"20":2,"391":1,"392":1,"591":1}
const keys = Object.keys(obj).sort((a, b) => a - b).map(Number);
// [1,2,4,5,10,20,391,392,591]
const out = keys.map((key) => {
return obj[key] > 1 ? Array(obj[key]).fill(key) : key;
});
// [[1,1,1,1],[2,2,2],4,5,10,[20,20],391,392,591]
console.log(JSON.stringify(out));
You can use reduce and then Array.fill. Here the reduce will create an object like this
{
"1": 4,
"2": 3,
"4": 1,
"5": 1,
"10": 1,
"20": 2,
"391": 1,
"392": 1,
"591": 1
}
which mean there are 4 1s, 3 2s and so on. Then you can use array fill after iterating this object. The array fill syntax is arr.fill(value[, start[, end]])
So in our case we will case new Array(k[keys]).fill(+keys, 0, k[keys]) is creating a new array of length 4,3 so on except for 1 and from 0th index it is filling with the key
let arr = [1, 2, 4, 591, 392, 391,1, 2, 5, 10, 2, 1, 1, 1, 20, 20];
let k = arr.reduce(function(acc, curr) {
if (curr in acc) {
acc[curr] += 1;
} else {
acc[curr] = 1
}
return acc;
}, {});
let grouped = [];
for (let keys in k) {
if (k[keys] !== 1) {
grouped.push(new Array(k[keys]).fill(+keys, 0))
} else {
grouped.push(+keys)
}
}
console.log(grouped)

Merge elements of array with comma with max counter

So I have an array of ids something like this:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
I need a function that will be called like mergeArray(arr, 3), and it should return comma separated values with maximum of 3 elements like this:
const newArr = ['1,2,3', '4,5,6', '7,8,9', '10,11'];
How can I do this? If possible with ES6 functions for simpler code.
slice your array into 3 lengths arrays and directly join them
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
const mergeArray = (arr, size) => {
let res = [];
for (i = 0; i < arr.length; i += size) {
res.push(arr.slice(i, i + size).join(','));
}
return res;
}
console.log(mergeArray(arr, 3));
You can split() the array into the specific size and join() them before pushing into the resulting array:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
var i, j, newArr=[], size = 3;
for (i=0,j=arr.length; i<j; i+=size) {
newArr.push(arr.slice(i, i+size).join());
}
console.log(newArr);
One of the ways to do it is with Array.prototype.reduce and Array.prototype.map:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
function mergeArray(arr, n) {
return arr
.reduce((all, el, i) => {
const ind = Math.floor(i/n);
all[ind] = [...all[ind] || [], el]
return all;
},[])
.map(a => a.join(','))
}
console.log(mergeArray(arr, 3));
You could join the array and match the wanted parts with a regular expression.
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
result = data.join(',').match(/\d+(,\d+(,\d+)?)?/g)
console.log(result);

JavaScript. How to Compare Input Arrays

I'm stuck with this problem for 3 days now... Someone please help me.
Challenge 5
Construct a function intersection that compares input arrays and returns a new array with elements found in all of the inputs.
function intersection(arrayOfArrays) {
}
console.log(intersection([[5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]]));
// should log: [5, 15]
Reduce the arrays to a Map of counts, with the value as key. Spread the Map to entries. Use Array.filter() on the Map's entries to remove all entries, which value is not equal to the arrayOfArrays lenth. Extract the original number from the entries using Array.map():
function intersection(arrayOfArrays) {
return [...arrayOfArrays.reduce((r, s) => {
s.forEach((n) => r.set(n, (r.get(n) || 0) + 1));
return r;
}, new Map())]
.filter(([k, v]) => v === arrayOfArrays.length)
.map(([k]) => k);
}
console.log(intersection([[5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]]));
You could reduce the array by filtering with just checking if the other array contains the value.
This works for arrays with unique values.
Array#reduce:
If no initialValue is provided, then accumulator will be equal to the first value in the array, and currentValue will be equal to the second.
The callback
a.filter(v => b.includes(v))
filters array a. If the array b includes the value of a, then this value v is included in the accumulator for the next iteration or as final result.
accumulator currentValue new accumulator
a b result
-------------------- -------------------- --------------------
[ 5, 10, 15, 20] [15, 88, 1, 5, 7] [ 5, 15]
[ 5, 15] [ 1, 10, 15, 5, 20] [ 5, 15]
function intersection(arrayOfArrays) {
return arrayOfArrays.reduce((a, b) => a.filter(v => b.includes(v)));
}
console.log(intersection([[5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]]));
First try to find out the intersection of two arrays which is the base problem. Then try to build up for variable number of arrays passed as arguments for intersection. You can use reduce() for doing that.
function intersectionOfTwoArrays(arr1, arr2)
{
return arr1.filter(x => arr2.some(y => y === x));
}
function intersection(...arrayOfArrays)
{
return arrayOfArrays
.reduce((a, b) => intersectionOfTwoArrays(a, b));
}
intersection(
[5, 10, 15, 20],
[15, 88, 1, 5, 7],
[1, 10, 15, 5, 20]
);
You can go through the first array in the array of arrays and check which of its value is present in all the other arrays.
Here is an example:
function intersection(input) {
let firstArray = input[0];
let restOfArrays = input.splice(1);
return firstArray.filter(v => restOfArrays.every(arr => arr.includes(v)));
}
const input = [[5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]];
const result = intersection(input);
console.log(result);
Works with even if there is duplicate in same array.. like in my example added 5 twice in arrayEle[1];
var arrayEle = [[5, 10, 15, 20], [15, 88, 1, 5, 5], [1, 10, 15, 5, 20]]
var startIndex = 1;
var newArray = [];
for (var x = 0; x < arrayEle[0].length; x++) {
var temVal = 1;
var value;
for (var y = 1; y < arrayEle.length; y++) {
for (var z = 0; z < arrayEle[y].length; z++) {
if (arrayEle[y][z] == arrayEle[0][x]) {
temVal++;
value = arrayEle[y][z];
break;
}
}
}
if (temVal == arrayEle.length) {
newArray.push(value);
console.log(value);
}
}
console.log(newArray);
//log: [5, 15]
I think you want the common elements. Let me show you how:
var Array1 = [5, 10, 15, 20]
var Array2 = [15, 88, 1, 5, 7]
var Array3 = [1, 10, 15, 5, 20]
var found = []
var Final = []
var c = 1;e = 1;
for (i = 1;i<=Array1.length;i++){
for (k = 1;k<=Array2.length;i++){
if (Array1[i] == Array2[k]){
Found[c] = Array[i];
c++;
}
}
}
for (n = 1;n <= Found.length ; n++){
for (m = 1;m <= Array3.length ; n++){
if (Found[n] == Array3[m]){
Final[e] = Found[n]
e++;
}
}
}
//the Array Final Contains 5 , 15

Categories