Most efficient way of continuously going through an array of nth length? - javascript

I'm trying to go through an array with a fixed number of items and but the number of times I go through the array is unknown and can loop.
The result is supposed to be like red > blue > green > yellow > red > ...
What's the most efficient way to do this?
for (let i=0; i< nth; i++) {
console.log(color(i));
};
function color(x){
var colorArr = ['red','blue','green','yellow'];
*** Code here ***
return colorArr[i];
};

You can determine the "expected index" in this way
const expectedIndex = i % colorArr.length;
It means that whenever the i >= length_of_the_array, then "expected index" will be restart.
Debugging:
nth = 6;
colorArr.length = 4
==> So when i = 0, 1, 2, 3 is fine.Then i = 4, 5 the modular value is exactly expected index. (More details you can see in the console log below)
var nth = 6;
for (let i = 0; i < nth; i++) {
console.log(color(i));
};
function color(i){
var colorArr = ['red','blue','green','yellow'];
const expectedIndex = i % colorArr.length;
// Remove the line below if you don't want to log debugging value
console.log({i, length: colorArr.length, expectedIndex});
return colorArr[expectedIndex];
};

This is the type of problem that generators are great at solving. Generators are a standard way to let you get a (potentially infinite) series of elements, one at a time. While they're very elegant, they have a bit of a learning curve, so if haven't used them before and you just want to get the job done, go with #Phong's solution.
function* cycle(elements) {
while (true) {
yield* elements;
}
}
// Example usage //
const COLORS = ['red', 'blue', 'green'];
console.log('Use the generator in a loop');
for (const color of cycle(COLORS)) {
console.log(color);
if (Math.random() > 0.5) break;
}
console.log('Use the generator by itself');
const colorGenerator = cycle(COLORS);
console.log(colorGenerator.next().value);
console.log(colorGenerator.next().value);
console.log(colorGenerator.next().value);
console.log(colorGenerator.next().value);
console.log(colorGenerator.next().value);

Related

How can I simplify this generator to eliminate the recursion?

I'm trying to create a generator that yields values between a given range. My requirements are:
all emitted values are unique
the order of values is the same every time the generator is run
each value is far away from previously emitted values
it is not known how many values will be generated
I've decided to model this as a tree, and doing something like a breadth first search to split the range up into even sized subdivisions, and iterating over each layer in an order that avoids adjacent node visiting.
I've come up with the following solution which works, however I don't like that it is using recursion, and I suspect it can be rewritten to eliminate the recursion (maybe a queue?) A bit stuck here. Here's what I have so far:
function* orderedSubdivisor(start: number, end: number): Generator<number> {
const mid = (end - start) / 2 + start
yield mid
const left = orderedSubdivisor(start, mid)
const right = orderedSubdivisor(mid, end)
while (true) {
yield left.next().value
yield right.next().value
}
}
const iter = orderedSubdivisor(0, 64)
console.log(Array.from({length: 63}, () => iter.next().value))
thanks!
You can model this using a binary counter to represent the position/path in your tree. The least significant bit decides whether you are in the left or right half of the top branch, the second-least significant bit decides whether you are in the left or right half on the second level, and so on:
function* orderedSubdivisor(start, end) {
for (let i=1; true; i++) {
let sum = start;
let part = end-start;
for (let j=i; j; j=j>>>1) {
part /= 2;
if (j & 1) sum += part;
}
yield sum;
}
}
const iter = orderedSubdivisor(0, 64)
console.log(Array.from({length: 63}, () => iter.next().value))
In fact you can see that you've essentially just created a counter, but flip the bit order of every yielded value:
function* orderedSubdivisor(start, end) {
const mid = (end - start) / 2 + start
yield mid
const left = orderedSubdivisor(start, mid)
const right = orderedSubdivisor(mid, end)
while (true) {
yield left.next().value
yield right.next().value
}
}
let i=0;
for (const v of orderedSubdivisor(0, 64)) {
if (i++ >= 63) break;
document.body.appendChild(document.createElement('pre')).textContent = v.toString(10).padStart(2)+': 0b'+v.toString(2).padStart(6, '0');
}
I'm trying to create a generator that yields values between a given range. My requirement [is] to have each value far away from previously emitted values.
My actual use case is mapping to hues in a colour wheel.
For that, I recommend the fibonacci hashing technique with the golden ratio/golden angle, which provides a very evenly distributed output around the colour wheel:
function* orderedSubdivisor(start, end) {
for (let i=0; true; i+=0.6180339887498951) {
yield start+(i%1)*(end-start);
}
}
let i=0;
for (const v of orderedSubdivisor(0, 360)) {
if (i++ >= 100) break;
const p = document.body.appendChild(document.createElement('p'));
p.textContent = v;
p.style = `background-color: hsl(${v}deg, 100%, 50%)`;
}

Design a layout sorting algorithm

I'm trying to come up with an algorithm to make sure my items fit into the screen. These items are randomly generated and have a score of either 1, 2, or 4. This score lets met know how much space they take up on the screen. Score 4 means it takes up 4x the size of a score 1 item. It's important to note that an item with a score of 1 always needs a 'buddy', so they take up the width of the page.
I want to fit up to a score of 6 on my page, to an infinite amount of pages.
A valid result could be [ [1, 1, 2, 2], [4, 2] ]. Each array in the root array is its own page, so this would mean I have 2 pages that are properly filled since their child scores count up to 6.
Result:
This is what I came up with, but it's not so bulletproof. I'm not so good at writing these kinds of algorithms. Perhaps someone could help me in the right direction?
It's okay to skip items like I'm doing, but I'm also skipping items that might find a match later. Currently, all skipped items will be added to the front of items before sortItems is called again. So they will just be sorted with the next batch of items to find a new match.
const getItemScore = (size) => {
switch (size) {
case 'small':
return 1;
case 'medium':
return 2;
case 'large':
return 4;
default:
console.error('Unknown size:', size);
}
}
const sortItems = (items) => {
const maxPageScore = 6;
let sorted = [];
let perPage = [];
let smallSort = [];
let skippedItems = [];
let currentPageScore = 0;
items.forEach((item) => {
const itemScore = getItemScore(item.size);
if (currentPageScore + itemScore < maxPageScore) {
// Item fits in page
if (item.size === 'small') {
// A small item needs to have a 'buddy'
if (smallSort.length < 2) {
// the small item can be added
smallSort.push(item);
}
if (smallSort.length === 2) {
// we have found a buddy for the item
smallSort.forEach((smallItem) => {
perPage.push(smallItem);
});
// reset smallSort
smallSort = [];
// increment pageScore
currentPageScore += 2;
}
}
else if (item.size === 'medium' || item.size === 'large') {
// medium and large can always be added if their score isnt more than maxPageScore
perPage.push(item);
currentPageScore += itemScore;
}
}
else if (currentPageScore + itemScore === maxPageScore) {
// we have a full page
perPage.push(item);
sorted.push(perPage);
// reset values
perPage = [];
smallSort = [];
currentPageScore = 0;
}
else {
// item doesnt fit in page
skippedItems.push(item);
}
});
// done looping over items
const result = {
sorted: sorted,
skipped: skippedItems,
};
return result;
}
The intuition would tell us to come up with a recurrence-relation so we can reduce the problems into smaller-subproblems.
Lets say we are calculating for size = N
The top-section could either be:
2 blocks of 1: [1,1] ; which leaves us with size = N - 1
1 block of 2: 2 ; which leaves us with size = N - 1
1 block of 4: 4 ; which leaves us with size = N - 2
Say, S(n) = #ways to arrange these blocks, then:
S(n) = S(n-1) + S(n-1) + S(n-2)
^from-(1) ^from-(2) ^from-(3)
which becomes:
S(n) = 2S(n-1) + S(n-2)
with boundary conditions:
S(0) = 0
S(1) = 2
This makes it quite easy to solve:
def get_pattern_combs(N):
if N < 1:
return 0
if N == 1:
return 2
lval = 0
val = 2
for i in range(2, N+1):
new_val = 2*val + lval
lval = val
val = new_val
return val

Synaptic / Neataptic simple NEAT XOR solution

EDIT: I managed to get together couple of simple examples https://github.com/developer239/neural-network-playground
Could anyone help me with simple neat example teaching the net how to solve XOR or some other similar problem? But using the NEAT technique so that I would not have to specify training data set?
Using javascript: https://github.com/cazala/synaptic or https://github.com/wagenaartje/neataptic
1. Initialize network
2. Generate generation
3. Go through each genome in generation and evaluate its fitness (how good it is)
4. Take 2 best genomes from generation
5. Merge genomes 50 / 50 at random
6. Mutate final genome
7. Generate second generation
This would be extremely helpful. Same teqnique is being used here:
https://github.com/ivanseidel/IAMDinosaur
https://www.youtube.com/watch?v=P7XHzqZjXQs
I went through the source code but there is WAY to much stuff going on. I understand the general idea. However I have no idea how to implement the solution.
Thank you :)
There is an example on Neataptic's README.md.
// this network learns the XOR gate (through neuro-evolution)
var network = new Network(2,1);
var trainingSet = [
{ input: [0,0], output: [0] },
{ input: [0,1], output: [1] },
{ input: [1,0], output: [1] },
{ input: [1,1], output: [0] }
];
await network.evolve(trainingSet, {
equal: true,
error: 0.03
});
Neataptic has it all built-in so all you have to provide is a data set. If you need more info on how this has been set up, read this article.
For problems with dynamic solutions, a custom loop and fitness function has to be implemented.
I know this is quite an old question, and neataptic isn't very widely used, but I found a much simpler way to implement this so i thought i'd share
const { Neat } = require('neataptic');
function fitness(network) {
let score = 0;
score += Math.abs(0 - network.activate([0,0])[0]);
score += Math.abs(1 - network.activate([0,1])[0]);
score += Math.abs(1 - network.activate([1,0])[0]);
score += Math.abs(0 - network.activate([1,1])[0]);
score = -score;
return score;
}
(async () => {
const neat = new Neat(2 ,1 ,fitness, {});
for (let i = 0; i < 10000; i++) {
await neat.evolve();
}
const fittest = neat.getFittest();
console.log(fitness(fittest));
console.log(fittest.activate([0,0]));
console.log(fittest.activate([0,1]));
console.log(fittest.activate([1,0]));
console.log(fittest.activate([1,1]));
})();
I managed to write my own solution. You can find it here: https://github.com/developer239/neural-network-playground/tree/master/neatXOR
The main difference from the solution in documentation is that in genetic.js you can dynamically change the learning process.
This is entry file:
const genetic = require('./genetic')
genetic.generateRandomPopulation()
for (let iteration = 0; iteration < 1000; iteration += 1) {
genetic.live()
genetic.evolve()
}
const genom = genetic.neat.population[0]
console.log(`
Result for genom with index 0 in the newest population. Note that selection / mutation happened
after we called last evolve function so this is not necessarily the best genome in the population.
[0, 0] = ${genom.activate([0, 0])} (should be 0)
[1, 1] = ${genom.activate([1, 1])} (should be 0)
[0, 1] = ${genom.activate([0, 1])} (should be 1)
[1, 0] = ${genom.activate([1, 0])} (should be 1)
`)
This is genetic.js file:
const { Neat, architect } = require('neataptic')
module.exports = {
neat: null, // https://wagenaartje.github.io/neataptic/docs/neat/
possibleInputs: [
[0, 0], // expected output 0
[1, 1], // expected output 0
[0, 1], // expected output 1
[1, 0], // expected output 1
],
generateRandomPopulation: function () {
this.neat = new Neat(
2, // number of inputs
1, // number of outputs
null, // fitnessFunction - in this example we are calculating fitness inside live method
{
elitism: 5, // this sets how many genomes in population will be passed into next generation without mutation https://www.researchgate.net/post/What_is_meant_by_the_term_Elitism_in_the_Genetic_Algorithm
mutationRate: 0.3, // sets the mutation rate. If set to 0.3, 30% of the new population will be mutated. Default is 0.3
network: // https://wagenaartje.github.io/neataptic/docs/architecture/network/
new architect.Random(
2,
3,
1,
),
},
)
},
// the closer the output gets to expectedOutput the better
// note that optimal fitness in this example is 0 neural network seems to work fine though
calculateFitness: function (expectedOutput, output) {
let closeCount = Math.abs(expectedOutput - output)
let fitness = closeCount * -1
return fitness
},
live: function () {
// increment generation index
this.neat.generation += 1
// loop through each genome
for (let genomeIndex in this.neat.population) {
const possibleInputs = this.possibleInputs
const genome = this.neat.population[genomeIndex]
genome.score = 0
// loop through each input
for (let i = 0; i < possibleInputs.length; i += 1) {
let input = possibleInputs[i]
// test each input
let output = genome.activate(input)[0]
// calculate fitness for each output
// we have 4 different inputs so the total score is sum of 4 different fitness values
if (i <= 1) {
genome.score += this.calculateFitness(0, output)
} else {
genome.score += this.calculateFitness(1, output)
}
}
}
},
evolve: function () {
const neat = this.neat
console.log(`[generation ${neat.generation}] Average score: ${neat.getAverage()} (the closer to zero the better)`)
// sort by genome.score in descending order
neat.sort()
// our new population will be here
let newPopulation = []
// we want to push neat.elitism number of best genomes into the new population automatically
for (let i = 0; i < neat.elitism; i++) {
newPopulation.push(neat.population[i])
}
// we want to get offspring from the current population and push it into the new population
for (let i = 0; i < neat.popsize - neat.elitism; i++) {
newPopulation.push(neat.getOffspring())
}
// set new population
neat.population = newPopulation
// mutate the population
neat.mutate()
},
}

Adding numbers together

I want to loop over an array whilst addding the numbers together.
Whilst looping over the array, I would like to add the current number to the next.
My array looks like
[0,1,0,4,1]
I would like to do the following;
[0,1,0,4,1] - 0+1= 1, 1+0= 1, 0+4=4, 4+1=5
which would then give me [1,1,4,5] to do the following; 1+1 = 2, 1+4=5, 4+5=9
and so on until I get 85.
Could anyone advise on the best way to go about this
This transform follows the specified method of summation, but I also get an end result of 21, so please specify how you get to 85.
var ary = [0,1,0,4,1],
transform = function (ary) {
var length = ary.length;
return ary.reduce(function (acc, val, index, ary) {
if (index + 1 !== length) acc.push(ary[index] + ary[index + 1]);
return acc;
}, []);
};
while (ary.length !== 1) ary = transform(ary);
If you do in fact want the answer to be 21 (as it seems like it should be), what you are really trying to do is closely related to the Binomial Theorem.
I am not familiar with javascript, so I will write an example in c-style pseudocode:
var array = [0,1,0,4,1]
int result = 0;
for (int i = 0; i < array.length; i++)
{
int result += array[i] * nChooseK(array.length - 1, i);
}
This will put the following numbers into result for each respective iteration:
0 += 0 * 1 --> 0
0 += 1 * 4 --> 4
4 += 0 * 6 --> 4
4 += 4 * 4 --> 20
20 += 1 * 1 --> 21
This avoids all the confusing array operations that arise when trying to iterate through creating shorter-and-shorter arrays; it will also be faster if you have a good nChooseK() implementation.
Now, finding an efficient algorithm for a nChooseK() function is a different matter, but it is a relatively common task so it shouldn't be too difficult (Googling "n choose k algorithm" should work just fine). Some languages even have combinatoric functions in standard math libraries.
The result I get is 21 not 85. This code can be optimised to only use single array. Anyway it gets the job done.
var input = [0, 1, 0, 4, 1];
function calc(input) {
if (input.length === 1) {
return input;
}
var result = [];
for (var i = 0; i < input.length - 1; i++) {
result[i] = input[i] + input[i + 1];
}
return calc(result);
}
alert(calc(input));
This is an O(n^2) algorithm.

Javascript challenge - which basket contains the last apple?

I'm presented with the following challenge question:
There are a circle of 100 baskets in a room; the baskets are numbered
in sequence from 1 to 100 and each basket contains one apple.
Eventually, the apple in basket 1 will be removed but the apple in
basket 2 will be skipped. Then the apple in basket 3 will be removed.
This will continue (moving around the circle, removing an apple from a
basket, skipping the next) until only one apple in a basket remains.
Write some code to determine in which basket the remaining apple is
in.
I concluded that basket 100 will contain the last apple and here's my code:
var allApples = [];
var apples = [];
var j = 0;
var max = 100;
var o ='';
while (j < max) {
o += ++j;
allApples.push(j);
}
var apples = allApples.filter(function(val) {
return 0 == val % 2;
});
while (apples.length > 1) {
for (i = 0; i < apples.length; i += 2) {
apples.splice(i, 1);
}
}
console.log(apples);
My question is: did I do this correctly? What concerns me is the description of "a circle" of baskets. I'm not sure this is relevant at all to how I code my solution. And would the basket in which the remaining apple reside be one that would otherwise be skipped?
I hope someone can let me know if I answered this correctly, answered it partially correct or my answer is entirely wrong. Thanks for the help.
So, ... I got WAY too into this question :)
I broke out the input/output of my last answer and that revealed a pretty simple pattern.
Basically, if the total number of items is a power of 2, then it will be the last item. An additional item after that will make the second item the last item. Each additional item after that will increase the last item by 2, until you reach another item count that is again divisible by a power of 2. Rinse and repeat.
Still not a one-liner, but will be much faster than my previous answer. This will not work for 1 item.
var items = 100;
function greatestPowDivisor(n, p) {
var i = 1;
while(n - Math.pow(p, i) > 0) {
i++;
}
return Math.pow(p, (i - 1));
}
var d = greatestPowDivisor(items, 2)
var last_item = (items - d) * 2;
I believe Colin DeClue is right that there is a single statement that will solve this pattern. I would be really interested to know that answer.
Here is my brute force solution. Instead of moving items ("apples") from their original container ("basket") into a discard pile, I am simply changing the container values from true or false to indicate that an item is no longer present.
var items = 100;
var containers = [];
// Just building the array of containers
for(i=0; i<items; i++) {
containers.push(true);
}
// count all containers with value of true
function countItemsLeft(containers) {
total = 0;
for(i=0; i<containers.length; i++) {
if(containers[i]) {
total++;
}
}
return total;
}
// what is the index of the first container
// with a value of true - hopefully there's only one
function getLastItem(containers) {
for(i=0; i<containers.length; i++) {
if(containers[i]) {
return(i);
}
}
// shouldn't get here if the while loop did it's job
return false;
}
var skip = false;
// loop through the items,
// setting every other to false,
// until there is only 1 left
while(countItemsLeft(containers) > 1) {
for(i=0; i<containers.length; i++) {
if(containers[i]) {
if(skip) {
skip = false;
} else {
containers[i] = false;
skip = true;
}
}
}
}
// what's the last item? add one to account for 0 index
// to get a human readable answer
var last_item = getLastItem(containers) + 1;
Needs error checking, etc... but it should get the job done assuming items is an integer.

Categories

Resources