Given an index of 5, and an array size of 10, this array is returned: [5, 4, 6, 3, 7, 2, 8, 1, 9, 0]
Code:
function middleOutIterator(index, arraySize) {
var distances = [];
for (var i = 0; i < arraySize; i++) {
distances[i] = [ i, Math.abs(index - i) ];
}
distances.sort(sort);
for (var i = 0; i < distances.length; i++) {
distances[i] = distances[i][0];
}
return distances;
}
function sort(a, b) {
return a[1] > b[1];
}
Basically, you pass in a starting index, and it iterates outward in either direction.
This is not a true iterator, it merely creates an array of indices, so the name I gave it is a bit of misnomer, but what would you call this kind of iteration/sorting?
I'm not looking to optimize this function as it's not in a crucial area and certainly not a bottleneck, but I am interested in reading more about it and any related algorithms.
This type of iteration was recommended in the initial paper on Robin Hood hashing, where it was used in the searching step when doing lookups. The paper refers to it as "mean-centric searching," since the idea is to jump to the (expected) middle of a range and search outwards in both directions around the mean.
I'm not sure if this is the "official" name of this technique or whether it goes by many names, but it's nice to have something to point to.
Related
Consider that we have an array of length n being filled with random numbers, i want to write a function that would loop through an array and get the two(or more) indexes that satisfy a condition together.
For instance:
const arr = [12, 10, 2, 3, 17, 42, 56, 38]
write a function to get the two indexes such that if you multiplied their elements, it would bring out the largest answer. (56*42 would be the answer in this scenario)
I understand that in this case, you could just multiply the largest array element with the second largest, however a question of this nature could be much more complex and there could be much more conditions to solve for and the elements in the array could also be unknown. i am merely after the principle of the answer. If you could provide a solution to this question whilst briefly explaining how you came across your answer, it would be much appreciated.
When you know, that your accumulation function is steady, then you can simply order the array and return the indices of the two largest elements.
If you do not know, that the accumulation function is steady, then you can pairwise calculate the result of such function and, if the result is larger than your current cumulated value, remember the indices of the elements, which generated this value.
A function like this one can solve the problem with all accumulation functions passed as parameter:
const findHighestIndices = (values, accumlationFunction) => {
let currentMaximum = -Infinity;
let indices = [];
for (let i = 0; i < values.length; i++) {
for (let j = 0; j < values.length; j++) {
if (i === j) continue; // we only want to compare DIFFERENT elements
const cummulation = accumlationFunction(values[i], values[j]);
if (cummulation <= currentMaximum) continue;
currentMaximum = cummulation;
indices = [i, j];
}
}
return indices;
};
const arr = [12, 10, 2, 3, 17, 42, 56, 38];
console.log(findHighestIndices(arr, (a, b) => a * b));
When there is no order of parameters of the accumulation function, my implementation is highly optimizable, as you won't need to run the elements for both, i and j.
Not a native javascript developer, hope this can help.
I would loop over the list the number of indices expected to statisfy the condition and test the condition. Since, you don't want to use the same index two times, pass in this case.
const arr = [12, 10, 2, 3, 17, 42, 56, 38]
var max = -Infinity;
var max_i = 0
var max_j = 0
for(var i=0; i< arr.length; i++) {
for(var j=0; j< i+1; j++){
if(i==j){
//pass
}
var mul = arr[i]*arr[j];
if (mul > max){max = mul;max_i = i; max_j = j}
}}
The resulting indices are max_i and max_j.
I am trying to write code that reverses an array in place without using the reverse function (I'm busy learning JS so just doing an exercise from Eloquent JavaScript).
function reverseArrayInPlace(arr) {
for (let i = 0; i < arr.length; i++) {
arr[i] = arr[(arr.length - 1) - i];
}
return arr;
}
This was the code that I wrote which doesn't quite work, I know this is because I have already reassigned arr[0] and arr[1] so if I call reverseArrayInPlace([1, 2, 3, 4 ,5]), [5, 4, 3, 4, 5] is returned.
This was given as the solution:
function reverseArrayInPlace(array) {
for (let i = 0; i < Math.floor(array.length / 2); i++) {
let old = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = old;
}
return array;
}
Could anyone please explain what's happening in the solution so I can better understand? Thanks :)
So here is what is happening in this function:
for(let i = 0; i < Math.floor(array.length / 2); i++):
they are using the Math.floor() method to make sure that you only iterate through half of the array. That is why your original solution repeated elements instead of reversing them.
let old = array[i]:
This is a temporary variable to hold the element at the current index in the loop while you swap them.
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = old;
this swaps the elements.
which only leaves return array;
You only need to loop over half of the array since you are swapping items; if you loop over the entire array, you will swap each item twice, not changing the array at all. In each iteration, you just copy over the value at the reflected index, instead of transposing the two values, for which you need a temporary variable to store one of the values.
Say you have an array [1, 2, 3, 4, 5]. The code starts from left most element, and swap it with the right most element. so you get [5, 2, 3, 4, 1]. Then it does the same for the next element in the array, swap it with the second to right element, and you'll get [5, 4, 3, 2, 1]. Math.floor(array.length) make sure that the already swapped elements don't swap again, so it will only go through the first half of the array.
Given a rotate function like the one below, which rotates the array a set number of slots.
Is there an equivalent Ramda.js function or composition that will do this rotation?
var test = [1,2,3,4,5,6,7,8,9];
function rotate(arr, count) {
arr = arr.slice();
while (count < 0) {
count += arr.length;
}
count %= arr.length;
if (count) {
arr.splice.apply(arr, [0, 0].concat([].slice.call(arr.splice(arr.length - count, count))));
}
return arr;
}
example
rotate(test, 2) // -> [8, 9, 1, 2, 3, 4, 5, 6, 7]
Here's a point-free one liner which takes the count first and the data second, consistent with ramda's composable style:
const rotate = pipe(splitAt, reverse, flatten);
Of course you can always flip(rotate) to get a data first version.
UPDATE
Sorry, I read too fast and assumed the normal, left-wise direction for the rotation (eg, as it is in ruby). Here's a variation of the idea that does what your original does:
const rotate = pipe(useWith(splitAt, [negate, identity]), reverse, flatten);
This is similar to #donnut's answer, but includes modulo arithmetic to handle counts which exceed the length of the given list:
var rotate2 = function(xs, count) {
var n = -(count % xs.length);
return R.concat(R.slice(n, Infinity, xs),
R.slice(0, n, xs));
};
Here's a mutation-free equivalent which doesn't use Ramda at all:
var rotate3 = function(xs, count) {
var n = -(count % xs.length);
return xs.slice(n).concat(xs.slice(0, n));
};
Both solutions are significantly more declarative than the solution in the original post.
You could try:
function reverse(arr, count) {
return R.concat(R.slice(arr.length-count, arr.length, arr), R.slice(0, arr.length-count, arr));
}
See http://bit.ly/1G90ny8
I have two arrays where I need to compare values and get the duplicates. I wrote most of the code but seem to be stumped on the comparison.
Here is my code:
function compare(arr1, arr2) {
for (var i = 0; i< arr1.length; i++) {
for (var j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
console.log[i];
}
}
}
}
compare([5, 3, 2, 5, 1, 6], [6, 4, 2, 7, 10]);
I get the for loops to print all of the numbers, but for some reason the if statement comparison doesn't work. Is there something I am not getting about comparing values in arrays?
I am not looking for a straight up answer but guidance if possible.
Your code is quadratic in time since it iterates the second array for each item in the first array. A linear time solution is to convert the first array into a hash table, and then, for each item in the second one, instantly check if it is in the hash.
function intersect(a, b) {
var hash = {};
a.forEach(function(x) { hash[x] = 1 });
return b.filter(function(x) { return hash[x] === 1 });
}
c = intersect([5, 3, 2, 5, 1, 6], [6, 4, 2, 7, 10]);
document.write(c)
Do note, however, that this only works if items to compare are primitives, you cannot put objects in a hash, so the code has to be quadratic:
function intersect(a, b) {
return a.filter(function(x) {
return b.indexOf(x) >= 0
});
}
a = {x:'a'};
b = {x:'b'};
c = {x:'c'};
d = {x:'d'};
i = intersect([a,b,c], [a,b,d]);
document.write(JSON.stringify(i));
Regarding your bit about improving your current code, I suggest that you make your javascript more idiomatic, in particular,
get used to iteration methods instead of for loops
check the repertoire of built-in functions and use them wherever possible
and, for sanity's sake, never ever use ==
What would be the best way to shuffle an array of numbers with the condition that each number must be +3 or -3 of the next/prev number? So, for example [0,1] wouldn't work, but [0,3] would.
Thanks!
Looking at the screenshot it seems you're wanting to pick a random assortment from the list, with no 2 choices being within 3 of each other.
This code takes an array, and gives you a subset of the array satisfying that condition.
You can specify a maximum number of selections too, although you might not always get that many.
var src = [0,1,2,3,4,5,6,7,8,9,10,11,12];
var getRnd = function(max){
var output = [];
var newSrc = src.slice();
var test, index, i, safe;
while (newSrc.length > 0 && output.length < max){
index = Math.floor(Math.random()*newSrc.length);
test = newSrc.splice(index,1);
//Make sure it's not within 3
safe = true;
for (i=0; i<output.length;i++){
if(Math.abs(test-output[i]) < 3){
//abort!
safe=false;
}
}
if(safe){
output.push(test);
}
}
return output;
};
alert(getRnd(4));
A way (likley not the fastes) would be to:
sort array
pick random element to start new shuffled array with (mark element in sorted array as used or remove)
with binary search find next element that is +3 or -3 for the last one (randomly pick between -3 and +3). Make sure element is not marked as used before (otherwise find another one)
repeat 3 till you can find elements.
you either picked all elements from sorted array or such shuffling is not possible.
I think you get O(N*logN) with this (sorting N*logN and picking N elements with logN for each serch).
Assuming that the values in the array cannot be duplicated.
function one(array, mod){
var modArray = [];
for(var index in array){
var item = array[index];
var itemMod = item%3;
if(itemMod === mod){
modArray.push(item);
}
}
return modArray();
}
function two(modArray){
var sortedArray = // sort highest to lowest
for(var index in sortedArray ){
var item = array[index];
if(index > 0 && item[index-1] === item[index]-3){
}else{return false;}
}
return sortedArray.length;
}
function main(array){
var a1 = one(array, 0);
var a2 = one(array, 1);
var a3 = one(array, 2);
var a1c = two(a1);
var a2c = two(a2);
var a3c = two(a3);
return // if a1c is greatest then a1, if a2c greatest then a2 ... etc
}
I think you must be using the phrase "shuffle" in some non-standard way. If all of the numbers are already within +-3 of each other, then sorting the array will put them in the right order, unless there are duplicates, I guess.
More examples would probably be helpful. For instance, are these examples valid, and the sort of thing you're looking for?
[0, 3, 3] -> [3, 0, 3]
[9, 3, 6, 0, 6] -> [0, 3, 6, 9, 6]
[3, 3, 6, 0, 6] -> [0, 3, 6, 3, 6]
It feels like this is probably a solved problem in graph theory - some kind of network traversal with a maximum/minimum cost function.