Find unique number in unsorted array JavaScript - javascript

I have to find a unique number in unsorted array, but my function returns wrong number, I can't understand why.
Here is my code:
function findUniq(arr) {
let sorted = [...arr].sort();
if (sorted.length === 0) return 0;
// do magic
let num = 0;
for (let i = 1; i < sorted.length; i++) {
if (sorted[num] !== sorted[i]) {
num++;
sorted[num] = sorted[i];
}
}
return num + 1;
}
const testArray = [9, 7, 7, 9, 6, 6, 5, 5, 5];
console.log(findUniq(testArray));
if I invoke findUniq([9,7,7,6,6,5,5,5]) it gives 4. What do I do wrong? Thanks in advance. I forgot to mention I have to have just one for loop to implement O(n) time complexity

I don't know why your solution doesn't work, but here is working code:
const arr = [9,9,7,7,8,6,1,6,5,5,5]
function findUnique(arr){
const sorted = [...arr].sort()
if(sorted[0] !== sorted[1]) return sorted[0]
if(sorted[sorted.length - 1] !== sorted[sorted.length - 2]) return sorted[sorted.length - 1]
for(let i = 0; i < sorted.length; i++){
if(sorted[i] !== sorted[i - 1] && sorted[i] !== sorted[i + 1]) return sorted[i]
}
return "no unique"
}
console.log(findUnique(arr))

This should work:
It returns only one unique number in array or undefined
If you want all unique numbers replace return arr[0] with return arr. It will then return array of all unique numbers (or empty array if there are not any)
function findUniq(arr) {
arr.filter((item, index) => {
arr.splice(index, 1)
const unique = !arr.includes(item)
arr.splice(index, 0, item)
return unique
})
return arr[0]
}
ES6 aproach:
function findUniq(arr) {
return arr
.map((c) => arr.filter((b) => c == b))
.filter((e) => e.length < 2)
.reduce((total, cur) => total.concat(cur), [])
}

You can use reduce and can find the item that repeats once in the last index.
var arr = [9,7,7,6,6,5,5,5]
var uniqueNumber;
arr.reduce((obj,val,index) =>
{
obj[val] ? ++obj[val] : obj[val] = 1;
if(index == (arr.length - 1))
{
uniqueNumber = Object.keys(obj).find(key => obj[key] === 1)
}
return obj
},{})
console.log(uniqueNumber)

To do it in a single O(n) loop, reduce, keeping track of counts as well as a set of singular items.
function findUniq(arr) {
let [single] = arr.reduce((acc, el) => {
if (!acc[el]) acc[el] = 0;
if (++acc[el] === 1) acc.singular.add(el);
else acc.singular.delete(el);
return acc;
}, { singular: new Set() }).singular;
return single;
}
const input = [2, 2, 9, 7, 7, 6, 6, 5, 5, 5];
const result = findUniq(input);
console.log(result);

Related

Is there any other simple way to change my vanilla JavaScript code?

Is there a way I can make my code even more simple?
FYI, I'm a beginner and I've been learning JavaScript only for a week.
Thank you!
let array = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
// from above to [[1, 1, 1, 1], [2, 2, 2], 4, 5, 10, [20, 20], 391, 392, 591]
const answer = (arr) => {
arr.sort((a, b) => {
return a - b;
});
let counter = 0;
arr.forEach((num, i) => {
if (arr[i] === arr[i+1]) {
counter++;
} else if (arr[i] !== arr[i + 1] && arr[i] === arr[i-1]) {
arr[i-counter] = arr.slice(i-counter, i + 1);
counter = 0;
}
});
arr.forEach((num, i) => {
while (arr[i][0] && arr[i][0] === arr[i + 1]) {
arr.splice(i + 1, 1);
}
});
return arr;
}
const newArray = answer(array);
console.log(newArray);
Another option. First push each number in object's appropriate array, then convert object to resulting array as needed.
let arr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
const obj = {}, res = [];
for(e of arr) !obj[e] ? obj[e] = [e] : obj[e].push(e);
for(a in obj) obj[a].length === 1 ? res.push(obj[a][0]) : res.push(obj[a]);
console.log(res);
You can make it simpler just first sort and then group them.
let array = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20],
last = null;
const result = array
.sort((a, b) => a - b)
.reduce((acc, curr, index, arr) => {
// Getting the next element in array
const next = arr[index + 1];
if (last && last === curr) acc[acc.length - 1].push(curr);
else if (next && next === curr) acc.push([curr]);
else acc.push(curr);
// Changing the last to the curr
last = curr;
return acc;
}, []);
console.log(result);
Approach that uses a Map to group the elements then sorts the Map entries by key so as not to mutate original array at all
let array = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
const answer = (arr) =>{
const m = new Map();
arr.forEach(n => m.set(n, (m.get(n) || []).concat(n)));
return [...m.entries()].sort(([a],[b])=> a-b)
.map(([k,v]) => v.length > 1 ? v : v[0])
}
console.log(answer(array))

trying to find element of array from which sum of left side of array is equal to sum of right side of array in JavaScript

I am trying to find element of array from which sum of left side of array is equal to sum of right side of array in JavaScript
I am using:
function findEvenIndex(arr)
{
//Code goes here!
let num = 0;
function check(i){
console.log(arr);
console.log(num)
let arrPart1 = arr.slice(0,i).reduce(((a,b)=>a+b),0);
console.log(arrPart1)
let arrPart2 = arr.slice(i+1,arr.length).reduce(((c,d)=>c+d),0);
console.log(arrPart2)
if(arrPart2 === 0){
return -1
}
else if(arrPart1 !== arrPart2){
num++;
check(num);
}
}
return check(num);
}
For array:
[1,100,50,-51,1,1]
Getting:
[ 1, 100, 50, -51, 1, 1 ]
0
0
101
[ 1, 100, 50, -51, 1, 1 ]
1
1
1
Error:
The array was: [1,100,50,-51,1,1]
: expected undefined to equal 1
I'd recommend abandoning the recursive solution and opting for an iterative one - in this situation, it's easier to debug. I've written a function that is easy to understand and can solve your problem here:
function findEvenIndex(arr)
{
for(let i = 0; i < arr.length; i++) {
let leftTotal = arr.slice(0, i).reduce((t, v) => t + v, 0);
let rightTotal = arr.slice(i + 1).reduce((t, v) => t + v, 0);
if (leftTotal === rightTotal) {
return i;
}
}
return -1;
}
First check if the array length is an even number
if (array.length % 2 === 1) {
return false;
}
Slice the array in half and reverse the 2nd half
let half = (array.length / 2);
let sub1 = array.slice(0, half);
let sub2 = array.slice(-half).reverse();
Then filter both and return matches
return sub1.filter((num, idx) => num === sub2[idx]);
const array1 = [1, 100, 50, -51, 1, 1];
const array2 = [5, 62, 8, 0, 0, 15, 62, -5];
const array3 = [0, 1, 0];
const mirroredValues = array => {
let half;
if (array.length % 2 === 1) {
return false;
} else {
half = (array.length / 2);
}
let sub1 = array.slice(0, half);
let sub2 = array.slice(-half).reverse();
return sub1.filter((num, idx) => num === sub2[idx]);
};
console.log(mirroredValues(array1));
console.log(mirroredValues(array2));
console.log(mirroredValues(array3));
I would do it like this:
const findElementIndex = (array, index = 0) => {
let arr_part_1 = array.slice(0, index).reduce(((a, b) => a + b), 0);
let arr_part_2 = array.slice(index + 1, array.length).reduce(((a, b) => a + b), 0);
return arr_part_1 === arr_part_2 ? index : index === array.length ? -1 : findElementIndex(array, index + 1);
};
console.log('Example 1: ', findElementIndex([1, 1, 10, 2]));
console.log('Example 2: ', findElementIndex([1, 1, 1, 10, 2]));
console.log('Example 3: ', findElementIndex([100, 1, 100]));
That one could be better from performance point of view (reduce only once)
function inTheMiddle(arr) {
let rightSum = arr.slice(2).reduce((total, item) => total + item, 0);
let leftSum = arr[0];
console.log(leftSum, rightSum);
for (let i = 2; i < arr.length; i++) {
if (leftSum === rightSum) {
return i-1;
}
leftSum += arr[i-1];
rightSum -= arr[i];
console.log(leftSum, rightSum);
}
return -1;
}
console.log("In the middle:", inTheMiddle([1,100,50,-51,1,1]))

Find and return longest sequence of ascending numbers in an array (Javascript)

Given an array of numbers, I am looking for a way to find the longest sequence with removing any outliers. So in other words, it doesn't necessarily have to be a sequence originally, but in the output it should be.
this: https://en.wikipedia.org/wiki/Longest_increasing_subsequence
converted to Javascript would do
for inputs...
[0,2,4,12,6] //expected output: [0,2,4,6]
[1,3,7,5] //expected output: [1,3,5]
[2,4,6,8] //expected output: [2,4,6,8]
[6,4,2,5] //expected output: [2,5]
//I thought maybe something like... but not luck
const cleanCodes = (codes) => {
var cleaned = codes.map((code, i) => {
if(i<codes.length-1){
if(code[i+1]>code){
return code;
}
}else{
return code;
}
})
return cleaned;
}
<script>
function doSomething(main) {
console.log(main)
var cop = Object.assign([], main)
cop.sort(function (a, b) { return a - b })
let arra = main.slice(main.indexOf(cop[0]))
//get diff mode
let diff = []
for (let i = 0; i < arra.length; i++) {
diff[i] = arra[i + 1] - arra[i]
}
diff.sort();
let counts = []
diff.forEach(function (x) { counts[x] = [x, Number(diff[x] || 0) + 1] })
let reg = counts.sort(function (a, b) {
return b[1] - a[1]
})[0][0]
let result = [arra[0]]
let temp = Object.assign([], arra);
for (let i = 1; i < arra.length; i++) {
if (temp[i - 1] == temp[i] - reg)
result[i] = temp[i]
else {
temp[i] = temp[i - 1]
}
}
console.log(result)
}
function test() {
doSomething([0, 2, 4, 12, 6]);
doSomething([1, 3, 7, 5]);
doSomething([2, 4, 6, 8]);
doSomething([6, 4, 2, 5])
}
</script>

Grouping continuous number as "from~to" strings in JavaScript array

I have an array with numbers.
var myArray = [1, 2, 3, 5, 8, 9, 10];
and I'd like to group them into a string with a from~to format until the next value is not continuous with the previous value, like the following example.
var outputArray = ["1~3", "5", "8~10"];
How to do that?
You could take a slightly shorter approach by using the index to check if the first element needs an new array or if the value is not in order.
For the second mapping, you could just join all elements.
function group(numbers) {
return numbers
.reduce((result, value, index, array) => {
if (!index || array[index - 1] + 1 !== value) {
result.push([value]);
} else {
result[result.length - 1][1] = value;
}
return result;
}, [])
.map(array => array.join('~'));
}
console.log(group([1, 2, 3, 5, 8, 9, 10]));
You can do this with Array.reduce() followed by Array.map():
const nums = [1, 2, 3, 5, 8, 9, 10]
const res = nums.reduce((acc, cur, idx, arr) => {
if (idx === 0 || cur - 1 > arr[idx - 1]) {
acc.push([cur])
} else {
acc[acc.length - 1].push(cur)
}
return acc
}, []).map(cur => cur.length > 1 ? cur.shift() + "~" + cur.pop() : cur[0])
console.log(res)
Go thru only one time all elements. Whenever there is pattern of numbers not in sequence, just put them in results array.
var myArray = [1, 2, 3, 5, 8, 9, 10];
let start = myArray[0];
let end = myArray[0];
const results = [];
for (let i = 1; i < myArray.length; i++) {
if (myArray[i] === (end + 1)) {
end = myArray[i];
} else {
results.push((start === end) ? `${start}` : `${start}~${end}`);
start = myArray[i];
end = myArray[i];
}
}
results.push((start === end) ? `${start}` : `${start}~${end}`);
console.log(results);
Click here for CodePen (or a Chinese(中文)version).
Basically just create a lastValue variable, and iterating the array. If the currentValue - 1 equals the lastValue then it's a continuous number. Create a new group once the condition failed.
In the final you just merge the groups with a string.
var newArray = [];
var tempArray = [];
var oldArray = [1, 2, 3, 5, 8, 9, 10];
var lastValue = null;
oldArray.forEach(value => {
if (lastValue != value - 1 || lastValue === null) {
tempArray.push([value, value]);
} else {
tempArray[tempArray.length - 1][1] = value;
}
lastValue = value;
});
tempArray.forEach(value => {
if (value[0] === value[1]) {
newArray.push(value[0].toString());
} else {
newArray.push(value.join("~"));
}
});
// OUTPUS: (3) ["1~3", "5", "8~10"]
document.write(JSON.stringify(newArray));
For typescript, this function takes a sorted array of numbers and groups them into a single string.
function convertNumberArrayToRangeString(numbers: number[]): string {
const delimiter = '~';
return numbers
.reduce((accumulator: string, currentValue: number, index: number, array: number[]) => {
if (index > 0 && array[index - 1] + 1 !== currentValue) {
if (index > 2 && array[index - 1] - array[index - 2] === 1) {
accumulator += delimiter + array[index - 1].toString();
}
accumulator += ',' + currentValue.toString();
} else if (index === 0 || index === array.length - 1) { // first or last
if (array[index - 1] === currentValue - 1) {
accumulator += delimiter;
} else if (index > 0) {
accumulator += ',';
}
accumulator += currentValue.toString();
}
return accumulator;
}, '');
}
const list = [1, 2, 3, 6, 7, 8]; // sorted unique list
const groupedList = convertNumberArrayToRangeString(list);
console.log(groupedList);
Output> "1~3,6~8"

Remove Only One Duplicate from An Array

I'm trying to only remove one of the 2s from an array, but my code removes all of them. My code is as follows:
var arr = [2,7,9,5,2]
arr.filter(item => ((item !== 2)));
and:
var arr = [2,7,9,2,2,5,2]
arr.filter(item => ((item !== 2)));
Both remove all the 2s. I thought about removing duplicates, where it works if there's only one duplicate - e.g.:
Array.from(new Set([2,7,9,5,2]));
function uniq(a) {
return Array.from(new Set(a))
}
But fails if there's multiple duplicates as it just removes them all, including any other duplicated numbers:
Array.from(new Set([2,7,9,9,2,2,5,2]));
function uniq(a) {
return Array.from(new Set(a))
}
Does anyone know how to only remove one of the 2s? Thanks for any help here.
You could use indexOf method in combination with splice.
var arr = [2,7,9,5,2]
var idx = arr.indexOf(2)
if (idx >= 0) {
arr.splice(idx, 1);
}
console.log(arr);
You could take a closure with a counter and remove only the first 2.
var array = [2, 7, 9, 2, 3, 2, 5, 2],
result = array.filter((i => v => v !== 2 || --i)(1));
console.log(result);
For any other 2, you could adjust the start value for decrementing.
var array = [2, 7, 9, 2, 3, 2, 5, 2],
result = array.filter((i => v => v !== 2 || --i)(2));
console.log(result);
There are various ways to do that; one relatively simple way would be to use indexOf; see this other post: https://stackoverflow.com/a/5767357/679240
var array = [2, 7, 9, 5, 2];
console.log(array)
var index = array.indexOf(2);
if (index > -1) {
array.splice(index, 1);
}
// array = [7, 9, 5, 2]
console.log(array);
you can follow the following method
var arr= [2,3,4,2,4,5];
var unique = [];
$.each(arr, function(i, el){
if($.inArray(el, unique) === -1) unique.push(el);
})
You can do:
const arr = [2, 7, 9, 2, 2, 5, 2];
const result = arr
.reduce((a, c) => {
a.temp[c] = ++a.temp[c] || 1;
if (a.temp[c] !== 2) {
a.array.push(c);
}
return a;
}, {temp: {}, array: []})
.array;
console.log(result);
Most simple way to filter all duplicates from array:
arr.filter((item, position) => arr.indexOf(item) === position)
This method skip element if another element with the same value already exist.
If you need to filter only first duplicate, you can use additional bool key:
arr.filter((item, position) => {
if (!already && arr.indexOf(item) !== position) {
already = true
return false
} else return true
})
But this method have overheaded. Smartest way is use for loop:
for (let i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) !== i) {
arr.splice(i,1);
break;
}
}

Categories

Resources