finding a subset of an array centred on a given item [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Am trying to find a better way to return a range of array values from an existing array.
For an list/array of numbers, say:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I want to select a range of 5 numbers centred around the a given number x.
(Psuedocode since I guess i'm really referring to array indexes here.. values don't matter just the position)
So if x is 4, we can return a range centred on that:
[2, 3, 4, 5, 6]
But if x is 2, we cannot centre the range, so we'd have to do our best and return:
[1, 2, 3, 4, 5]
... Not centered, but atleast we have returned 5 numbers.
Similarly if x is 10:
[5, 6, 7, 8, 9, 10]
... 10 is the limit, so cannot centre, so the 5 numbers are pushed backwards.
I've got this working in some JS code, but it feels like too much code with too many conditionals.
Wondering if there is any known method or algorithm that can help?

You can do something like this.
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function findSubset(arr, item) {
// check index
var index = arr.indexOf(item);
// if element not found then return
if (index == -1) return;
// if element is at starting position
// then return first 5 element
if (index < 3)
return arr.slice(0, 5);
// if elements at ending position
// then return last 5 elements
if (index > arr.length - 4)
return arr.slice(-5);
// otherwisse return elements based on the index
// within the required range
return arr.slice(index - 2, index + 3);
}
console.log(
findSubset(arr, 1),
findSubset(arr, 10),
findSubset(arr, 5),
findSubset(arr, 9),
findSubset(arr, 3)
)
A generic solution with a varying count.
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function findSubset(arr, item, count = 5) {
var index = arr.indexOf(item),
// calculate floor and ceil value for comparison
// and getting subset array
f = Math.floor(count / 2),
c = Math.ceil(count / 2);
if (index == -1) return;
if (index < c)
return arr.slice(0, count);
if (index > arr.length - c - 1)
return arr.slice(-count);
return arr.slice(index - 2, index + c);
}
console.log(
findSubset(arr, 1, 3),
findSubset(arr, 10, 7),
findSubset(arr, 5, 1),
findSubset(arr, 9, 4),
findSubset(arr, 8, 1),
findSubset(arr, 7, 3),
findSubset(arr, 3, 9)
)

You could move the found index by subtracting the half size and take a max value for negative indices and a min value for indices which are greater than the array length minus the size of the wanted sub array.
value array index adj max min
----- ------------------------------ ----- --- --- ---
v
2 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 1 -1 0 0
[ ]
v
5 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 4 2 2 2
[ ]
vv
10 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 9 7 7 5
[ ]
function getSub(array, value, size) {
var index = array.indexOf(value) - (size - 1) / 2,
max = Math.max(index, 0),
min = Math.min(max, array.length - size);
return array.slice(min, min + size);
}
console.log(getSub([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2, 5));
console.log(getSub([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, 5));
console.log(getSub([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10, 5));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Recipe of the below algorithm :
Create subset s of max length a.length.
Calculate starting index that is index of x minus half the length of s.
Adjust starting index to prevent index overflow.
Copy s.length items from a to s.
Return s.
Array s is guaranteed to be contained in array a since s is never bigger than a.
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function subset (a, x, n) {
var s = new Array(Math.min(a.length, n));
var j = a.indexOf(x) - Math.floor(s.length / 2);
// overlap to the left : [.[1]2 3 4]
if (j < 0) {
j = 0;
}
// overlap to the right : [1 2 3[4].]
else if (j > a.length - s.length) {
j = a.length - s.length;
}
for (var i = 0; i < s.length; i++) {
s[i] = a[j + i]
}
return s;
}
console.log("x = 2, n = 4, s =", subset(a, 2, 4).join(","));
console.log("x = 9, n = 4, s =", subset(a, 9, 4).join(","));
console.log("x = 5, n = 4, s =", subset(a, 5, 4).join(","));
console.log("x = 2, n = 5, s =", subset(a, 2, 5).join(","));
console.log("x = 9, n = 5, s =", subset(a, 9, 5).join(","));
console.log("x = 5, n = 5, s =", subset(a, 5, 5).join(","));
console.log("x = 5, n = 20, s =", subset(a, 5, 20).join(","));
However, hard to know if it's shorter than your own code since you didn't provide it :-|

Related

Find position of Paired Numbers in Array

let input arr=[9,4,4,8,90,4,9,4,4,4,4,4,4,4,4,4,7,9,2,4,4,4,4,4,8,4,4,4,4];
let output arr=[1,7,9,11,13,15,19,21,25,27];
Above is an input array of numbers which contain mostly 4, if there is a pair of 4 which means (Input elements has 2 of the number 4 consecutively), its array position will be displayed in the output array. I have tried my code below but I am still unsure on how to solve this :). May I know how to solve this?
console.clear();
let arr=[8,4,4,4,4,4,4,4,4,4,7,9,2,4,4,4,4,4,8,4,4,4,4];
console.log("his")
for (let i=0;i<arr.length;i++){
if (arr[i]!==arr[i+1] &&arr[i]!==4 ){
console.log(i)
}
if (arr[i]!==arr[i+1] &&arr[i+1]!==4 ){
console.log(i+1)
}
}
This is a possible solution:
console.clear();
let arr=[8,4,4,4,4,4,4,4,4,4,7,9,2,4,4,4,4,4,8,4,4,4,4];
let pair = false;
for (let i=0;i<arr.length;i++){
if (pair == false) {
if (arr[i]==arr[i+1]){
console.log(i)
pair = true; // show that we have found a pair
} // thus we skip a 'for' loop
}
else {
pair = false; // reset the pair variable
}
}
output: [1, 3, 5, 7, 13, 15, 19, 21]
Do you want this pair:
let arr=[8,4,4,4,4,4,4,4,4,4,7,9,2,4,4,4,4,4,8,4,4,4,4];
to be counted, as well?
You could look to the next item and if the last index is not in the result array, the add the actual index to the result.
const
input = [9, 4, 4, 8, 90, 4, 9, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 9, 2, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4],
result = input.reduce((r, v, i, a) => {
if (v === a[i + 1] && r[r.length - 1] !== i - 1) r.push(i);
return r;
}, []);
console.log(...result);
An approach for n elements with a closure over a counting variable c.
const
getIndices = (array, n) => input.reduce((c => (r, v, i, a) => {
if (!c) {
if (v === a[i + 1]) c = 1;
return r;
}
c = v === a[i - 1] ? c + 1 : 0;
if (c === n) {
r.push(i - n + 1);
c = 0;
}
return r;
})(0), []),
input = [9, 4, 4, 8, 90, 4, 9, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 9, 2, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4];
console.log(...getIndices(input, 2));
console.log(...getIndices(input, 3));
console.log(...getIndices(input, 4));
console.log(...getIndices(input, 5));

JS Number of occurences in a sequence is a prime number

I have two arrays (X and Y) and I need to create array Z that contains all elements from array X except those, that are present in array Y p times where p is a prime number.
I am trying to write this in JS.
For Example:
Array X:
[2, 3, 9, 2, 5, 1, 3, 7, 10]
Array Y:
[2, 1, 3, 4, 3, 10, 6, 6, 1, 7, 10, 10, 10]
Array Z:
[2, 9, 2, 5, 7, 10]
So far I have this:
const arrX = [2, 3, 9, 2, 5, 1, 3, 7, 10]
const arrY = [2, 1, 3, 4, 3, 10, 6, 6, 1, 7, 10, 10, 10]
const arrZ = []
const counts = [];
// count number occurrences in arrY
for (const num of arrY) {
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
// check if number is prime
const checkPrime = num => {
for (let i = 2; i < num; i++) if (num % i === 0) return false
return true
}
console.log(counts[10]);
// returns 4
Any hint or help appreciated. Thanks!
You're on the right track. counts should be an object mapping elements in arrY to their number of occurrences. It's easily gotten with reduce.
The prime check needs a minor edit, and the last step is to filter arrX. The filter predicate is just a prime check on the count for that element.
// produce an object who's keys are elements in the array
// and whose values are the number of times each value appears
const count = arr => {
return arr.reduce((acc, n) => {
acc[n] = acc[n] ? acc[n]+1 : 1;
return acc;
}, {})
}
// OP prime check is fine, but should handle the 0,1 and negative cases:
const checkPrime = num => {
for (let i = 2; i < num; i++) if (num % i === 0) return false
return num > 1;
}
// Now just filter with the tools you built...
const arrX = [2, 3, 9, 2, 5, 1, 3, 7, 10]
const arrY = [2, 1, 3, 4, 3, 10, 6, 6, 1, 7, 10, 10, 10]
const counts = count(arrY);
const arrZ = arrX.filter(n => checkPrime(counts[n]));
console.log(arrZ)

Better way of doing: Always get a range of 6 Items out of an array

i need a little bit algorithm help.
I want to extract a range of 6 items out of an array. Starting point is a given index, if possible i want to get the items evenly split up before and after the given index.
I already did it, but i search for a more elegant way than just shifting the range. How can i improve my code?
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
const area = 7;
const currentIndex = 5;
const arrayLength = array.length;
let rangeBegin = currentIndex - Math.floor((area - 1) / 2);
let rangeEnd = currentIndex + Math.ceil((area - 1) / 2);
if (rangeBegin < 0) {
const offset = -rangeBegin;
rangeBegin += offset;
rangeEnd += offset;
}
if (rangeEnd >= arrayLength) {
const offset = rangeEnd - arrayLength;
rangeBegin -= offset;
rangeEnd -= offset;
}
slicedArray = array.slice(rangeBegin, rangeEnd);
console.log(slicedArray)
https://playcode.io/377252?tabs=script.js,preview,console
You could move the index by subtracting the half size and take a max value for negative indices and a min value for indices which are greater than the array length minus the size of the wanted sub array.
value array index adj max min
----- ------------------------------ ----- --- --- ---
v
2 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 1 -1 0 0
[ ]
v
5 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 4 2 2 2
[ ]
vv
10 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 9 7 7 5
[ ]
function getSub(array, index, size) {
if (size >= array.length) return array;
var pivot = Math.floor(index - (size - 1) / 2),
max = Math.max(pivot, 0),
min = Math.min(max, array.length - size);
return array.slice(min, min + size);
}
console.log(...getSub([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 1, 5));
console.log(...getSub([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 4, 5));
console.log(...getSub([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 9, 5));
console.log(...getSub([1, 2, 3, 4], 1, 5));
console.log(...getSub([1, 2, 3, 4], 4, 5));
console.log(...getSub([1, 2, 3, 4], 9, 5));
const array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17];
const area = 7;
const currentIndex = 5;
const arrayLength = array.length;
let rangeBegin = currentIndex - Math.floor((area - 1 ) /2);
if(rangeBegin < 0) {
rangeBegin = 0;
}
let rangeEnd = rangeBegin + area - 1;
if(rangeEnd >= arrayLength) {
rangeEnd = arrayLength;
rangeBegin = arrayLength - area;
}
slicedArray = array.slice(rangeBegin, rangeEnd);
!!! This code not checks if length of array lower than area we need.

Get 2 in 2 elements in array

I'm beginner and have one question.
I have one um array and need show just 2 in 2 elements of array elements, my code is:
var datas = [];
followTotalsData.forEach(function(dataByDay) {
datas.push(dataByDay[1]);
});
datas = [1, 2 , 3 , 4, 5, 6, 7, 8, 9, 10];
But I need the array formated as
var newDatas = [2, 4, 6, 8, 10];
I'm interpreting your question as
How can I only get Numbers that are multiples of 2 from my Array of Numbers
Use the remainder operator %.
If x % y is 0 then y divides x.
var datas = [1, 2 , 3 , 4, 5, 6, 7, 8, 9, 10];
var newDatas = datas.filter(function (e) {return e % 2 === 0;});
// [2, 4, 6, 8, 10]
Another solution:
var followTotalsData = [1, 2, 3, 4];
var result=[];
followTotalsData.forEach(function(data) {
if (data % 2 == 0 ) result.push(data);
});
console.log(result);
If you want every other element of the array, use the modulus function on the index of the array:
var datas = [1, 2 , 3 , 4, 5, 6, 7, 8, 9, 10];
var newDatas = datas.filter(function (e, index) {return index % 2 === 1;});
// [2, 4, 6, 8, 10]
var newDatas = datas.filter(function (e, index) {return index % 2 === 0;});
// [1, 3, 5, 7, 9]

lodash : how to loop with between a start value and end value

I've a for loop in javascript shown below. How to convert it to lodash for loop?
In such scenarios using lodash is advantageous over javascript for loop?
I've not used lodash much. Hence please advice.
for (var start = b, i = 0; start < end; ++i, ++start) {
// code goes here
}
You can use lodash range
https://lodash.com/docs/4.17.4#range
_.range(5, 10).forEach((current, index, range) => {
console.log(current, index, range)
})
// 5, 0, [5, 6, 7, 8, 9, 10]
// 6, 1, [5, 6, 7, 8, 9, 10]
// 7, 2, [5, 6, 7, 8, 9, 10]
// 8, 3, [5, 6, 7, 8, 9, 10]
// 9, 4, [5, 6, 7, 8, 9, 10]
// 10, 5, [5, 6, 7, 8, 9, 10]
I will imagine that b = 3 and end = 10 if I run your code and print the variables here is what I will get:
var b = 3;
var end = 10;
for (var start = b, i = 0; start < end; ++i, ++start) {
console.log(start, i);
}
> 3 0
> 4 1
> 5 2
> 6 3
> 7 4
> 8 5
> 9 6
To perform this with lodash (or underscore) I will first generate an array with range then iterate over it and gets the index on each iteration.
Here is the result
var b = 3;
var end = 10;
// this will generate an array [ 3, 4, 5, 6, 7, 8, 9 ]
var array = _.range(b, end);
// now I iterate over it
_.each(array, function (value, key) {
console.log(value, key);
});
And you will get the same result. The complexity is the same as the previous one (so no performance issue).
It seems there is no lodash way for writing loose for loops (those not iterating over a collection), but here is a simplified version of it:
for (var i = 0; i < end - b; i++) {
var start = i + b;
// code goes here
}

Categories

Resources