Related
I have two arrays:
A sequential array of numbers between 1-8, in increments of 1:
a = [1,2,3,4,5,6,7,8]
A sequential array of numbers between 1-8, with random increments:
b = [1,2,5,7]
I want to create a list of {a:val, b:val} dict pairs, where the value of b is only the next in the array if it is equal or greater to the value of a:
c = [
{a:1, b:1},
{a:2, b:2},
{a:3, b:2},
{a:4, b:2},
{a:5, b:5},
{a:6, b:5},
{a:7, b:7},
{a:8, b:7}
]
Is there an easy way to do this? I thought about using compounding $.each loops to build new arrays and increment values, but it seems as though this is overkill?
You can use map and shift
Loop over first array.
If the value of current element is greater then first element on second array remove first element from second array, ( except when the length is less then 2)
return object in desired format
let a = [1, 2, 3, 4, 5, 6, 7, 8]
let b = [1, 2, 5, 7]
let final = a.map(v => {
if (v >= b[1] && b.length > 1) {
b.shift()
}
return {
a: v,
b: b[0]
}
})
console.log(final)
This mutates second array if you don't want to mutate you can use a index variable and increment it based on condition
let a = [1, 2, 3, 4, 5, 6, 7, 8]
let b = [1, 2, 5, 7]
let index = 0
let final = a.map(v => {
if (v >= b[index+1] && b.length - 1 > index ) {
index++
}
return {
a: v,
b: b[index]
}
})
console.log(final)
The first array is actually redundant - the only significant information it carries is the number of elements.
The following code determines the difference between 2 adjacent threshold values from array b. This is 1 less the number of array elements with object property b set to the lower of these threshold values.
The target array is constructed as the array of object properties b in proper order. The resulting value list is mapped to the desired format.
The code may be optimized. It should run fast if the length of array b is much less than the length of array a. This hypothesis is not tested though and given the low complexity of the code/data structures will probably be insignificant.
let a = [1, 2, 3, 4, 5, 6, 7, 8]
, b = [1, 2, 5, 7]
, c = []
, n_last = 1
;
b.forEach ( (pn_current, pn_idx) => {
c.push( ...((new Array(pn_current - n_last)).fill(n_last)) );
n_last = pn_current;
});
c.push( ...((new Array(a.length + 1 - n_last)).fill(n_last)) );
c = c.map ( ( pn_entry, pn_idx ) => { return { a: pn_idx+1, b: pn_entry }; } );
console.log(c);
I have a place in my javascript code where I need to do an operation like
copying a specified range from one array into specified range in another array.
The operation is similar to
1) System.arraycopy in java ->
System.arraycopy(array1, index1, array2, index3, index4 - index4 + 1);
2) copy in go ->
copy(array2[index3:index4 + 1], array1[index1:index2+1])
3) slice in python ->
array2[index3: index4 + 1] = arr[index1: index2+1]
For now I am iterating it by hand and doing it.
But I did not any util function in js to do that. Is there really one ?
Update 1: It should exactly only copy and not add or remove elements from any of the two given arrays.
It should behave like this implementation:
function arraycopy(src, srcPos, dst, dstPos, length) {
let j = dstPos;
let tempArr = src.slice(srcPos, srcPos + length);
for (let e in tempArr) {
dst[j] = tempArr[e];
j++;
}
};
Update 2: (See some answers below with caution and see if it will fit your use case(like in huge dataset case)) Many answers below used splice in such a way it will break, if the range start to end in source array is huge. It will throw "RangeError: Maximum call stack size exceeded"... as it will exceed the maximum allowed number of arguments in a function. (try demo script here) "
A combination of slice and splice is probably the way to go here. You can write a helper function that mimics the same behavior in other languages. Here's one that mirrors Java's arraycopy method:
const arr1 = [1, 2, 3, 4, 5, 6];
const arr2 = ["a", "b", "c", "d", "e", "f"];
function arrayCopy(src, srcIndex, dest, destIndex, length) {
dest.splice(destIndex, length, ...src.slice(srcIndex, srcIndex + length));
}
// copy from arr1, at position 0, into arr2, at position 2, 3 elements.
arrayCopy(arr1, 0, arr2, 2, 3);
console.log(arr2)
Nothing similar in JavaScript. There might be JavaScript libraries with similar functionality, but I am not aware of any. Simple loop and assignment will be much more efficient, as it avoids the overhead from function calls and making new arrays :
function arraycopy(src, srcPos, dst, dstPos, length) {
while (length--) dst[dstPos++] = src[srcPos++]; return dst;
}
console.log( arraycopy([2,3,4,5,6], 1, [1,1,1,1,1,1], 2, 3) )
Another inefficient alternative for completeness, is copying the values with Object.assign :
function arraycopy(src, srcPos, dst, dstPos, length) {
return Object.assign(dst, Array(dstPos).concat(src.slice(srcPos, srcPos + length)))
}
console.log( arraycopy([2,3,4,5,6], 1, [1,1,1,1,1,1], 2, 3) )
Not a single function that I know of, but I think this functionality can be achieved using slice() and splice().
The slice() method slices out a piece of an array into a new array.
The splice() method can be used to add new items to an array.
Another approach would be to use slice to cut out the elements you need from the source array (without altering it), then forEach to replace elements from the distination array with the cut out elements:
function arraycopy(src, srcPos, dst, dstPos, length) {
src.slice(srcPos, srPos + length)
.forEach((e, i) => dst[dstPos + i] = e);
}
Example:
function arraycopy(src, srcPos, dst, dstPos, length) {
src.slice(srcPos, srcPos + length)
.forEach((e, i) => dst[dstPos + i] = e);
}
let arr1 = [0, 1, 2, 3, 4, 5, 6];
let arr2 = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
arraycopy(arr1, 2, arr2, 3, 3);
console.log("arr1: " + arr1);
console.log("arr2: " + arr2);
You can use the Array.prototype.splice() (along with the method Array.prototype.slice()) method to do exactly what you are describing.
Say you want to copy from index 3 to 5 (inclusive) out of array A into index 3 of array B (replacing anything in B from index 3 to 5):
const A = [0, 1, 2, 3, 4, 5, 6];
const B = ['a', 'b', 'c', 'd'];
const start = 3;
const end = 6;
// Splice (end - start) elements starting at 3
// with elements from start to end in A
B.splice(3, end - start, ...A.slice(start, end));
console.log(B);
Note: this also takes advantage of JavaScript's spread operator which emits all individual values from the array returned by A.slice().
Edit
Taking the following into consideration:
Update 1: It should exactly only copy and not add or remove elements from any of the two given arrays.
and
...it will break, if the range start to end in source array is huge.
Consider the following function:
function arrayCopy(arr1, index1, arr2, index2, length) {
return []
.concat(arr2.slice(0, index2)) // Array 2 from beginning until the index to replace
.concat(arr1.slice(index1, index1 + length)) // Array 1 from the index to copy for 'length' elements
.concat(arr2.slice(index2 + length)); // Rest of Array 2, 'length' elements past the index to replace
}
const A = [0, 1, 2, 3, 4, 5, 6];
const B = ['a', 'b', 'c', 'd'];
// Copy B into Z and replace Z[3] to Z[5] with A[3] to A[5]
const Z = arrayCopy(A, 3, B, 3, 3);
console.log('\'A\' after copy:');
console.log(A);
console.log('\'B\' after copy:');
console.log(B);
console.log('\'Z\' after copy:');
console.log(Z);
// Testing the method with arrays of length 2,000,000
const longArray = [];
const otherLongArray = [];
for (let i = 0; i < 2000000; i++) {
longArray.push(i);
otherLongArray.push(-i);
}
const newLongArray = arrayCopy(longArray, 0, otherLongArray, 1500000, 1000000);
console.log(newLongArray.length);
This will create a new array that is a copy of the second input array, but replaces length number of elements in that array (starting at index2) with length number of elements from the first input array (starting at index1). The function utilizes Array.prototype.concat() which takes a full array as an argument. This should alleviate the "callstack" error problem when the array is really large.
You can use the slice method to copy a range of elements from one array to another, and keeps to original array untouched.
The slice method accepts two arguments, the first one is the start index of the copy operation, the second argument is the end index of the copy operation, the end index is not included in the result array.
Here's an illustration of what being said:
var arr1 = ['Hi ', 'there! ', 'How ', 'are ', 'you ?'];
var arr2 = arr1.slice(2, arr1.length);
console.log(arr2.toString());
// output: How ,are ,you ?
Learn more about slice method.
JavaScript Array slice() and concat() Method fits your requirement.
var arr= ["a", "b", "c", "d", "e"];
var arr2 = ["x","y","z"];
arr= arr.slice(0, index3).concat(arr2.slice(index1: index2+1)).concat(arr.slice(index4+1, arr.length));
HTML file for trial
Got this question recently:
Write a function which takes an array of arrays (each of which contains numbers sorted from largest to smallest), and a number (n). Return the n largest numbers.
For example:
findLargest([ [10, 5, 3, 1], [9, 8, 7, 6], [11, 2, 1, 0] ], 5)
=> [11, 10, 9, 8, 7]
findLargest([ [15, 5, 3, 1], [10, 8, 7, 6]], 3)
=> [ 15, 10, 8 ]
Do this without copying or modifying the arrays (just read from them).
Optimize for time complexity.
I came up with this, but am not that happy with my solution:
function findLargest(numberArrays, n ) {
var results = [];
var pointers = [];
for (var x = 0; x < numberArrays.length; x++) {
pointers.push(0);
}
while (results.length < n) {
var subMaxes = [];
for (var i = 0; i < pointers.length; i++) {
var point = pointers[i];
subMaxes.push(numberArrays[i][point]);
}
var max = Math.max.apply(null, subMaxes);
var indexOfMax = subMaxes.indexOf(max);
pointers[indexOfMax]++;
results.push(max);
}
return results;
}
I think it is O(n^2).... is there anyway to do it in O(n)?
The question can be formalised (and slightly tweaked) as, Given a 2D array of dimension n x n, where each row is sorted in a decreasing order, find the largest k elements
For the largest n elements, the time complexity will be O(nlogn). The procedure for k largest elements is explained below:
Build a max heap of the first element from each row: Time complexity is O(n)
Extract the largest element from the heap, and insert an element into the heap from the row to which the extracted element belongs. Time Complexity is O(logn)
Repeat under desired number of elements is extracted.
So an iteration to extract the largest number requires O(logn) time, with a pre-processing O(n) cost.
To extract k elements, the time complexity of the above algorithm is O(klogn)
Merge all arrays into single array. This takes O(n) time.
Use median of medians algorithm to find kth largest element in new array. O(n) time.
Traverse array and grab all elements greater than or equal to that element. This takes O(n) time.
This algorithm runs in O(n) time.
I have four arrays A,B.C, and D. For example:
length of A is 1
length of b is 4
length of C is 1
length of D is 2.
var a = [1];
var b = [2,3,4,5];
var c = [6];
var d = [7,8];
I want to concat those four arrays based on the larger length of the arrays, so the arrays will be in order: b,d,a,c:
Expected result:
[2,3,4,5,7,8,1,6]
[2,3,4,5,1,6,7,8] //also valid, a and c are same length, so can be sorted this way too.
How can I find the larger to lower arrays and concat them from larger to smaller in JavaScript?
It's simple enough using sort and concat:
Array.prototype.concat.apply([], [a, b, c, d].sort(function (a, b) {
return b.length - a.length;
}));
Array.prototype.concat.apply is used to join the child arrays together.
You could do this quite neatly with underscore:
_.sortBy([a,b,c,d], function(num) {
return num.length;
}).reverse().join(',').split(',');
Mine's more verbose but still seems to work; the idea in all first 3 answers is to put the arrays into an additional array, then do a custom sort of the arrays based on their length. A good if somewhat dated reference is at: http://www.javascriptkit.com/javatutors/arraysort.shtml
var arrays = [a, b, c, d];
var concatentation = [];
arrays.sort(function(x, y) {
return y.length - x.length;
});
for (var i=0, n=arrays.length; i<n; i++) {
concatentation = concatentation.concat(arrays[i]);
}
console.log(concatentation); //[2, 3, 4, 5, 7, 8, 1, 6]
I have a series of values which correspond to certain numbers. There are never two values that correspond to the same number. There are no gaps between the numbers.
E.G.
{a: 1, b: 2, c: 3, d: 4}
as opposed to
{a: 1, b: 3, c: 4, d: 7}
Right now, I store the values in an array and find the index of that value. The index in the array is the number that value corresponds with.
Assume the arrays are prepopulated. My questions is which is more efficient to find the corresponding numbers in Javascript:
Store the values in specific positions of an array and find the index with indexOf().
---or---
Store the values and numbers as key value pairs in an associative array.
from what you are saying...
a should be zero as the array starts from index zero and not 1
CASE numeric array:{a: 1, b: 2, c: 3, d: 4}
for loop is suitable
var a = [];
a[5] = 5;
for (var i=0; i<a.length; i++) {
// Iterates over every single numeric indexes from 0 to 5
}
CASE a value is skipped:{a: 1, b: 3, c: 4, d: 7}
for..in is suitable
var a = [];
a[5] = 5;
for (var x in a) {
ignores 0-4,shows only 5
}
CASE Associative array: indexof is suitable
NOTE: It is considered bad practice for iterating through arrays,but not for iterating through members of an object.