Array truncation with splice method - javascript

I need to delete occurrences of an element if it occurs more than n times.
For example, there is this array:
[20,37,20,21]
And the output should be:
[20,37,21]
I thought one way of solving this could be with the splice method
First I sort the array it order to make it like this:
[20,20,37,21]
Then I check if the current element is not equal to the next and split the array into chunks, so it should look like:
[20, 20],[37],[21]
Later I can edit the chunk longer than 1 and join it all again.
This is what the code looks like in my head but didn't work in real life
var array = [20, 37, 20, 21];
var chunk = [];
for(i = 0; i < array.length; i++) {
if(array[i] !== array[i + 1]) {
var index = array.indexOf(array[i]);
chunk.push = array.splice(0, index) // cut from zero to last duplicate element
} else
var index2 = a.indexOf(a[i]);
chunk.push(a.splice(0, index));
}
with this code the output is
[[], [20, 20]]
I think It's something in the 'else' but can't figure it out what to fix.

As the logic you want to achieve is to delete n occurrences of element in an array, your code could be as follow:
var array = [1, 1, 3, 3, 7, 2, 2, 2, 2];
var n = 2;
var removeMultipleOccurences = function(array, n) {
var filteredArray = [];
var counts = {};
for(var i = 0; i < array.length; i++) {
var x = array[i];
counts[x] = counts[x] ? counts[x] + 1 : 1;
if (counts[x] <= n) filteredArray.push(array[i])
}
return filteredArray;
}
console.log(removeMultipleOccurences(array, n));

I came up with this one, based on array filter checking repeated values up to a limit, but I can see #Basim's function does the same.
function removeDuplicatesAbove(arr, max) {
if (max > arr.length) {max = arr.length;}
if (!max) {return arr;}
return arr.filter(function (v, i) {
var under = true, base = -1;
for (var n = 0; n < max; n++) {
base = arr.indexOf(v, base+1); if (base == -1) {break;}
}
if (base != -1 && base < i) {under = false;}
return under;
});
}
var exampleArray = [20, 37, 20, 20, 20, 37, 22, 37, 20, 21, 37];
console.log(removeDuplicatesAbove(exampleArray, 3)); // [20, 37, 20, 20, 37, 22, 37, 21]

Always when you use splice() you truncate the array. Truncate the array with the length of same values from the start with the help of lastIndexOf(). It always starts from 0.
[ 1, 1, 1, 2, 2, 2, 3, 4, 4, 5 ] // splice(0, 3)
[ 2, 2, 2, 3, 4, 4, 5 ] // splice(0, 3)
[ 3, 4, 4, 5 ] // splice(0, 1)
[ 4, 4, 5 ] // splice(0, 2)
[ 5 ] // splice(0, 1)
Do this as long as the array length is greater than 0.
var arr = [1, 1, 1, 2, 2, 2, 3, 4, 4, 5];
var res = [];
while (arr.length > 0) {
var n = arr[0];
var last = arr.lastIndexOf(n) + 1;
res.push(n);
arr.splice(0, last);
}
console.log(res);

You can use Array.prototype.reduce(), Array.prototype.filter() to check if n previous elements are the same as current element
let cull = (arr, n) => arr.reduce((res, curr) => [...res
, res.filter(v => v === curr).length === n
? !1 : curr].filter(Boolean), []);
let arrays = [[20,37,20,21], [1,1,3,3,7,2,2,2,2]];
let cullone = cull(arrays[0], 1);
let cullthree = cull(arrays[1], 3);
console.log(cullone // [20, 37, 21]
, cullthree // [1, 1, 3, 3, 7, 2, 2, 2]
);

Related

How do i reverse an array in javaScript without .reverse()

I'm trying to reverse the contents of an array. My approach works well when the contents of the said array are of same type. but once they're of different types it just doesn't work. Constraint is that i can't use the .reverse() method and if possible, without creating a new array.
The answer in this question is close to what i want but i don't understand it.
Here is my code...
reverse.js
#!/usr/bin/node
exports.rev = function (list) {
for (let i = 0, j = (list.length - 1); i <= (list.length / 2); i++, j--) {
[list[i], list[j]] = [list[j], list[i]];
}
return (list);
};
main.js
#!/usr/bin/node
const rev = require('./reverse').rev;
console.log(rev([1, 2, 3, 4, 5]));
console.log(rev(["School", 89, { id: 12 }, "String"]));
Expected:
[5, 4, 3, 2, 1]
["String", { id: 12 }, 89, "School"]
What I got:
[5, 4, 3, 2, 1]
["String", 89, { id: 12 }, "School"]
I've found out that your code almost works. You just need to modify the condition a bit to
i < (list.length / 2) //not `<=`
function rev(list) {
for (let i = 0, j = (list.length - 1); i < (list.length / 2); i++, j--) {
[list[i], list[j]] = [list[j], list[i]];
}
return (list);
};
console.log(rev([1, 2, 3, 4, 5]));
console.log(rev(["School", 89, { id: 12 }, "String"]));
let array = [1, 2, 3, 4, 5]
let reverse = [];
for (var i = array.length - 1; i >= 0; i--){
reverse.push(array[i]);
}
You can try with a for loop like this:
let arr = ["School", 89, { id: 12 }, "String"];
let newArr = [];
for (let i = arr.length - 1; i >= 0; i--) {
newArr.push(arr[i])
}
console.log(newArr);
Expected output: ["String", [object Object] { id: 12 }, 89, "School"]
You can user a recursion to reverse
You can use Spread operator(...) along with distructure assignment for that.
function rev(arr) {
const [first, ...rest] = arr
return arr.length > 1 ? [...rev(rest), first] : arr
}
console.log(rev([1, 2, 3, 4, 5]));
console.log(rev(["School", 89, { id: 12 }, "String"]));
const [first, ...rest] = arr is a shortcut for:
const first = arr[0]
const rest = arr.slice(1)
However, ...rev(rest) will spread items of returned array and spread them. So, [...rev(rest), first] will keep the output of rev first and then push first at the end of array.
If you are comfortable with mutation of original array, try this
function rev(arr) {
return arr.length > 1 ? [arr.pop(), ...rev(arr)] : arr
}
console.log(rev([1, 2, 3, 4, 5]));
console.log(rev(["School", 89, { id: 12 }, "String"]));
Already good answers (and examples of arrays) here
My try with native methods:
const rev = (arr) => {
len = arr.length;
for (i = 1; i<= len; i++) arr.splice(len-i,0,arr.shift());
}
const array = ["School", 89, { id: 12 }, "String"];
console.log("original",array);
rev(array);
console.log("reversed",array);

Get distinct duplicates from array

I have an array [1,1,1,1,2,3,4,5,5,6,7,8,8,8]
How can I get an array of the distinct duplicates [1,5,8] - each duplicate in the result only once, regardless of how many times it appears in the original array
my code:
var types = availControls.map(item => item.type);
var sorted_types = types.slice().sort();
availControlTypes = [];
for (var i = 0; i < sorted_types.length - 1, i++) {
if (sorted_types[i + 1] == sorted_types[i])
availControlTypes.push(sorted_types[i]);
}
This gets me the duplicates, but not unique.
This will do it
var input = [1, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8];
let filterDuplicates = arr => [...new Set(arr.filter((item, index) => arr.indexOf(item) != index))]
console.log(filterDuplicates(input))
You need a for loop, with an object that will hold the number of times the number appeared in the array. When the count is already 1, we can add the item to the result. We should continue to increment the counter, so we won't add more than a single duplicate of the same number (although we can stop at 2).
function fn(arr) {
var counts = {};
var result = [];
var n;
for(var i = 0; i < arr.length; i++) {
n = arr[i]; // get the current number
if(counts[n] === 1) result.push(n); // if counts is exactly 1, we should add the number to results
counts[n] = (counts[n] || 0) +1; // increment the counter
}
return result;
}
var arr = [1, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8];
var result = fn(arr);
console.log(result)
const dupes = arr =>
Array.from(
arr.reduce((acc, item) => {
acc.set(item, (acc.get(item) || 0) + 1);
return acc;
}, new Map())
)
.filter(x => x[1] > 1)
.map(x => x[0]);
const arr = [1, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8];
console.log(dupes(arr));
// [ 1, 5, 8 ]
ES6 1 liner.
This is very similar to how we find unique values, except instead of filtering for 1st occurrences, we're filtering for 2nd occurrences.
let nthOccurrences = (a, n = 1) => a.filter((v, i) => a.filter((vv, ii) => vv === v && ii <= i).length === n);
let x = [1, 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8];
let uniques = nthOccurrences(x, 1);
let uniqueDuplicates = nthOccurrences(x, 2);
let uniqueTriplets = nthOccurrences(x, 3); // unique values with 3 or more occurrences
console.log(JSON.stringify(uniques));
console.log(JSON.stringify(uniqueDuplicates));
console.log(JSON.stringify(uniqueTriplets));

Find a group of objects in an array with javascript

Question has been moved to CodeReview: https://codereview.stackexchange.com/questions/154804/find-a-list-of-objects-in-an-array-with-javascript
Having an array of objects - such as numbers - what would be the most optimal (Memory and CPU efficiency) way if finding a sub group of objects? As an example:
demoArray = [1,2,3,4,5,6,7]
Finding [3,4,5] would return 2, while looking for 60 would return -1.
The function must allow for wrapping, so finding [6,7,1,2] would return 5
I have a current working solution, but I'd like to know if it could be optimized in any way.
var arr = [
1,
5,2,6,8,2,
3,4,3,10,9,
1,5,7,10,3,
5,6,2,3,8,
9,1]
var idx = -1
var group = []
var groupSize = 0
function findIndexOfGroup(g){
group = g
groupSize = g.length
var beginIndex = -2
while(beginIndex === -2){
beginIndex = get()
}
return beginIndex
}
function get(){
idx = arr.indexOf(group[0], idx+1);
if(idx === -1 || groupSize === 1){
return idx;
}
var prevIdx = idx
for(var i = 1; i < groupSize; i++){
idx++
if(arr[getIdx(idx)] !== group[i]){
idx = prevIdx
break
}
if(i === groupSize - 1){
return idx - groupSize + 1
}
}
return -2
}
function getIdx(idx){
if(idx >= arr.length){
return idx - arr.length
}
return idx
}
console.log(findIndexOfGroup([4,3,10])) // Normal
console.log(findIndexOfGroup([9,1,1,5])) // Wrapping
You could use the reminder operator % for keeping the index in the range of the array with a check for each element of the search array with Array#every.
function find(search, array) {
var index = array.indexOf(search[0]);
while (index !== -1) {
if (search.every(function (a, i) { return a === array[(index + i) % array.length]; })) {
return index;
}
index = array.indexOf(search[0], index + 1);
}
return -1;
}
console.log(find([3, 4, 5], [1, 2, 3, 4, 5, 6, 7])); // 2
console.log(find([6, 7, 1, 2], [1, 2, 3, 4, 5, 6, 7])); // 5
console.log(find([60], [1, 2, 3, 4, 5, 6, 7])); // -1
console.log(find([3, 4, 5], [1, 2, 3, 4, 6, 7, 3, 4, 5, 9])); // 6
.as-console-wrapper { max-height: 100% !important; top: 0; }
My take on the problem is to use slice() and compare each subarray of length equal to the group's length to the actual group array. Might take a bit long, but the code is short enough:
// The array to run the tests on
var arr = [
1,
5, 2, 6, 8, 2,
3, 4, 3, 10, 9,
1, 5, 7, 10, 3,
5, 6, 2, 3, 8,
9, 1
];
// Check arrays for equality, provided that both arrays are of the same length
function arraysEqual(array1, array2) {
for (var i = array1.length; i--;) {
if (array1[i] !== array2[i])
return false;
}
return true;
}
// Returns the first index of a subarray matching the given group of objects
function findIndexOfGroup(array, group) {
// Get the length of both arrays
var arrayLength = array.length;
var groupLength = group.length;
// Extend array to check for wrapping
array = array.concat(array);
var i = 0;
// Loop, slice, test, return if found
while (i < arrayLength) {
if (arraysEqual(array.slice(i, i + groupLength), group))
return i;
i++;
}
// No index found
return -1;
}
// Tests
console.log(findIndexOfGroup(arr,[4,3,10])); // Normal
console.log(findIndexOfGroup(arr,[9,1,1,5])); // Wrapping
console.log(findIndexOfGroup(arr,[9,2,1,5])); // Not found
If the group is longer than the array, some errors might occur, but I leave it up to you to extend the method to deal with such situations.

Make average of values inside array to smooth graph line

I have an array which represents the points of a graph with different values like the following one:
var array = [5, 3, 4, 1, 2];
I would like to loop through it and create a new array where the new values are:
An average between the value preceding it and the one coming after it.
Placed among the existing ones.
This means that array[0] will remain at the same position, while the other values will be pushed of one position. The new array should look like this:
var newArray = [5, 4, 3, 3.5, 4, 2.5, 1, 1.5, 2];
Do you have an idea on how to achieve this? Thanks in advance to your replies!
var array = [5, 3, 4, 1, 2];
var newArr = [array[0]]; // start the array with the first from the original
array.reduce((a, b) => {
newArr.push((a + b) / 2, b);
return b;
});
console.log(newArr);
var array = [5, 3, 4, 1, 2];
var newArray = [];
newArray.push(array[0]);
for(var i=0; i < array.length-1; i++)
{
var first = array[i];
var second = array[i+1];
var avg = (first+second)/2;
newArray.push(avg);
newArray.push(second);
}
https://jsfiddle.net/5utkvge8/
You are going to want to loop through your original array, pushing each number to the new one, and if you are not on the final element, get the average of array[i] and array[i+1]
var array = [5, 3, 4, 1, 2];
var newArray = [];
for (var i = 0; i < array.length; i++)
{
newArray.push(array[i])
if (!isNaN(array[i+1]))
{
newArray.push((array[i] + array[i+1]) / 2)
}
}
or in a functional, no-side effects, way:
var array = [5, 3, 4, 1, 2];
var newArray = array.reduce((result, value, index, array) => result.concat(index > 0 && index < array.length ? [(array[index-1] + value)/2, value] : value), [])
In case you can modify the original array:
var array = [5, 3, 4, 1, 2],
len = array.length * 2 - 2;
for (var i = 1; i < len; i = i + 2) {
array.splice(i, null, (array[i-1] + array[i]) / 2);
}
console.log(array);
let createdArr = []
[5, 3, 4, 1, 2].forEach( (item,index,arr) => {
createdArr.push(item)
if( index !== 0 && index + 1 !== arr.length ){
createdArr.push( (item + arr[ index + 1]) / 2 )
}
} )

how to find longest common subarray

here is my problem: I have 5 arrays of integer like these in javascript:
array1 = [0, 1, 2, 3, 4];
array2 = [9, 1, 2, 3, 4];
array3 = [10, 1, 2, 11, 4];
array4 = [12, 1, 2, 13, 4];
array5 = [14, 1, 2, 15, 4];
I have to find the longest common subarray. In this case I have to retrieve the following subarray: [1, 2, 4].
For the records, I won't find repetitions inside arrays and my main goal is not execution speed.
thanks
here is the solution using Set in Javascript
var myArray = [array1 , array2 ,array3 , array4 ,array5];
let keys = new Set();
myArray.forEach(arr => arr.forEach(el => keys.add(el) ))
var common = [...keys].filter(key => myArray.every(arr => arr.includes(key)))
console.log(common);
#define MAX(a,b) a>b?a:b
int main(int argc, char* argv[])
{
if(argc < 2)
return -1;
int x = strlen(argv[1])+1;
int y = strlen(argv[2])+1;
int i,j,k,l;
int longest =0;
char* LCS = (char*)malloc(sizeof(char)*MAX(x,y));
int** arr = (int**)malloc(sizeof(int*)*x);
for(i=0;i<=y;i++)
arr[i] =(int*) malloc(sizeof(int)*y);
for(i=0;i<=x;i++)
for(j=0;j<=y;j++)
{
arr[i][j] = 0;
}
for(i=0;i<x;i++)
for(j=0;j<y;j++)
{
if(argv[1][i] == argv[2][j])
arr[i+1][j+1] = arr[i][j]+1;
if(arr[i+1][j+1] > longest)
{
longest =arr[i+1][j+1];
memset(LCS,0,MAX(x,y));
for( k=0,l=i;k<=longest;k++,l--)
LCS[k] = argv[1][l];
}
}
printf(" %s",argv[2]);
for(i=0;i<x;i++)
{
printf("\n%c",argv[1][i]);
for(j=0;j<y;j++)
{
printf("%d",arr[i][j]);
}
}
printf("\nLongest Common Subarray : %s\n",LCS);
return 0;
}
Try this:
var array1 = [0, 1, 2, 3, 4];
var array2 = [9, 1, 2, 3, 4];
var array3 = [10, 1, 2, 11, 4];
var array4 = [12, 1, 2, 13, 4];
var array5 = [14, 1, 2, 15, 4];
// join everything into one array
var all = array1.join(',')+','+array2.join(',')+','+array3.join(',')+','+array4.join(',')+','+array5.join(',');
all = all.split(',');
// get an object with all unique numbers as keys
var keys = {};
for(var i=0; i<all.length; i++) keys[all[i]] = 1;
console.log(keys);
// generate an array with values present in all arrays
var common = [];
for(var x in keys) {
if(array1.indexOf(parseInt(x)) != -1 && array2.indexOf(parseInt(x)) != -1 && array3.indexOf(parseInt(x)) != -1 && array4.indexOf(parseInt(x)) != -1 && array5.indexOf(parseInt(x)) != -1) {
common.push(x);
}
}
console.log(common);
I guess this can give you a good start:
My script will return you an object with the count of each elements. But for now, it takes the first array as base.
var array1 = [0, 1, 2, 3, 4];
var array2 = [9, 1, 2, 3, 4];
var array3 = [10, 1, 2, 11, 4];
var array4 = [12, 1, 2, 13, 4];
var array5 = [14, 1, 2, 15, 4];
var array6 = [13, 1, 2, 18, 4];
var mainArr = [array1, array2, array3, array4, array5, array6]
function getCommonElement(arr){
var subLength = arr[0].length;
var resultArr = new Array();
var ret = new Object();
for(var k=0;k<subLength;k++){
var temp = new Array();
for(var i=0;i<arr.length;i++){
temp.push(arr[i][k]);
}
resultArr.push(temp);
}
for(var i=0;i<arr[0].length;i++){
ret[arr[0][i]+''] = resultArr[i].join('').split(arr[0][i]+'').length - 1;
}
return ret;
}
Cheers.
/**
longest common subarray b/w 2 arrays
a = [2,3,4,5,6,7,8], b = [6,7,8,4,5,2,3]
ans = 6,7,8
basically create a 2d arr and if elements match dp[i][j] = 1 + dp[i-1][j-1];
if dp[i][j] > maxLen, update maxLen and store the index
Now that we have the maxLen, subarray will be from (index - maxLen) till index.
*/
int[] finMaxCommon(int[] a, int[] b){
int m = a.length, n = b.length, maxLen = 0;
int[][] dp = new int[m+1][n+1];
// i want a 0th row why? m->out of bounds; comparing i-1; i->1 then i-1 will be 0
for (int i = 1; i<=m; i++){
for(int j = 1; j<=n; j++){
if(a[i-1] == b[j-1]) {
dp[i][j] = 1 + dp[i-1][j-1];
maxLen = Math.max(maxLen, dp[i][j]);
}
}
}
// endIndex = 6, 3, a[6-3+1], a[6]
return new int[]{a[endIndex-maxLen+1], [endIndex]};
}
dry run
0,6,7,8,4,5,2,3
0, 0 //
2, 1 // (2,2) i = 1, j = 6 1 + dp[0][5]
3, 2 // (3,3) i = 2, j = 7 1 + dp[1][6]
4,
5,
6, 1
7, 2
8, 3

Categories