How to do uniform crossover in javascript? - javascript

I am new to javascript,I am pretty confused with this uniform crossover stuff
What is uniform crossover ?
I have two array Like this
var ParentOne = ["j1","j2","j3","j4","j5"];
var ParentTwo = ["j3","j4","j2","j1","j4"];
How to do it
I've just wrote just rand Selection array
function uniqueRandomInts(upperLimit, amount) {
var possibleNumbers = _.range(upperLimit + 1);
var shuffled = _.shuffle(possibleNumbers);
return shuffled.slice(0, amount);
}

http://codepen.io/anon/pen/BpBOoB
Since you're pretty new to js, the linked codepen is written in ES6 syntax. In particular, it makes use of destructuring to help with array length reordering and array concatenation and uses of const versus var.
In particular, there is a use case not covered by the currently accepted answer. What happens if the parents are not of equal size?
By just iterating over one parent or another, if that parent is shorter than the other then data from the second parent is lost. If the parent is longer than the other one, then both extra cycles are wasted because there is no matching data on the short parent and errors are introduced into the child array with undefined for each missing array index.
In the code below, we first sort the parent arrays so the shortest is first. After creating the child, we then concatenate any remaining data from the longest parent to the end of the child array.
const parentOne = ['j1','j2','j3','j4','j5'];
const parentTwo = ['j3','j4','j2','j1','j4'];
const parentThree = ['j1','j2','j3','j4','j5', '#', '##', '###'];
const parentFour = ['j3','j4','j2','j1','j4'];
const parentFive = ['j1','j2','j3','j4','j5', '#', '##', '###'];
const parentSix = ['j3','j4','j2','j1','j4'];
// ensure parentOne is the shortest
const fn = (...parents) => {
// ensure shortest parent is first
[parents] = parents[1].length < parents[0].length ? [[parents[1], parents[0]]] : [[parents[0], parents[1]]];
// iterate over shortest parent
let child = parents[0].map((item, i) => parents[Math.round(Math.random())][i]);
// add the remaining elements from the longest array to the child
if (parents[1].length > parents[0].length) {
child = [...child, ...parents[1].slice(parents[0].length)];
}
return child;
}
console.log(fn(parentOne, parentTwo));
console.log(fn(parentThree, parentFour));
console.log(fn(parentFive, parentSix));
console.log('---');

You could rely on the fact, that both parents arrays have the same length and then just map the random items to a new array.
var p1 = ["j1", "j2", "j3", "j4", "j5"],
p2 = ["j3", "j4", "j2", "j1", "j4"],
output = p1.map(function(_, i) {
return [p1, p2][Math.round(Math.random())][i];
});
console.log(output);
ES6
var parent1 = ["j1", "j2", "j3", "j4", "j5"],
parent2 = ["j3", "j4", "j2", "j1", "j4"],
crossover = (p1, p2) => p1.map((_, i) => [p1, p2][Math.round(Math.random())][i]),
output = crossover(parent1, parent2);
console.log(output);

It looks like you want to create an output array with each element selected randomly from one of two input arrays. This is simple to do with a loop and basic random and rounding functions.
var ParentOne = ["j1","j2","j3","j4","j5"],
ParentTwo = ["j3","j4","j2","j1","j4"],
parents = [ParentOne, ParentTwo],
output = []; output.length = ParentOne.length;
for (var i = 0; i < output.length; i++) {
output[i] = parents[Math.round(Math.random())][i]
}

Related

How to find max number from an array, but from selected elements only in javascript

This is my array from which I want to find max.
number = {"abc": [43,4,34,34,6,444], "dsfsd":[324,324,32,43,34,2] };
console.log((Math.max(...number[abc]));
Here the output is 444, and it's working fine. But now, I want to select max from selected indexs. I am storing those indexes in this array.
available = [0,2,3];
Now, index 0,2,3 of number[abc] are 43,34, 6
And I want 43 to be displayed, because it is the max from selected indexes.
How can I do it?
Map the indicies to the values, and then call Math.max on those values:
const number = {"abc": [43,4,34,34,6,444], "dsfsd":[324,324,32,43,34,2] };
const available = [0,2,3];
const availableValues = available.map(i => number.abc[i]);
console.log(Math.max(...availableValues));
You can create a reusable function that will have a custom logic to check the highest number instead of using Math.max(). Using reusable function will help you to scale the code without duplicating the logic.
var available = [0,2,3];
var number = {"abc": [43,4,34,34,6,444], "dsfsd":[324,324,32,43,34,2] };
function getHighest(available, number){
var index = available[0];
var highest = number[index];
for(var i=1; i<available.length; i++){
index = available[i];
if(highest < number[index]){
highest = number[index];
}
}
return highest;
}
var highest = getHighest(available, number['abc']);
console.log(highest);
You can also achview this by filtering the number.abc array.
const number = {"abc": [43,4,34,34,6,444], "dsfsd":[324,324,32,43,34,2] };
const available = [0,2,3];
const filtered = number.abc.filter((num, idx) => available.includes(idx));
console.log(Math.max(...filtered));

How to optimally interleave K arrays of same fixed N length in Javascript

I have the following data structure which is a list of lists.
Input Data:
const attributes = {
AO:(15174) [Number …]
jointId:(15174) [Number …]
paletteIdx:(15174) [Number …]
position:(15174) [Array(3) …]
normal:(15174) [Array(3) …]
....//additional variable amount of properties
}
expected output:
[AO[0], jointId[0], PaletteIdx[0], position[0][0],
position[0][1], position[0][2], normal[0][0],
normal[0][1], normal[0][2], AO[1], jointId[1], ...]
I need to interleave the lists into one combined flat array. I have tried a few different solutions (nested loops) that didn't seem to scale. My latest attempt is using eval for some code generation to coerce a nested loop solution into one pass.
const attributeNames = Object.keys(attributes);
const funcBody = attributeNames.map((attributeName) => {
return `attributes.${attributeName}[index],`;
}).join('\n');
const output = eval(`
attributes[attributeNames[0]].reduce((acc, value, index) => {
acc = acc.concat(${funcBody});
return acc;
}, []);
`);
This is a non frequent operation that I can maybe move to an offline process, unfortunately, that would be a large refactor of an existing system.
(By the way, to avoid browser interruptions, one can also utilize a web worker.)
Just going with your example, which did not include in the output an element I inserted to make one array longer than the other three, what I saw in the output was tantamount to a column by column traversal of the lists that also assumes they are of equal length.
We can easily code that with a for loop. Please include more specific details about what your needs are if this would not meet them. For elements that are arrays, we can use a destructuring assignment.
const attributes = {
AO:[1,2,3],
jointId:[4,5,6],
paletteIdx:[[7,8,9], [10,11,12], [13,14,15]],
position:[[16,17,18], [19,20,21], [22,23,24]]
}
const attributeNames = Object.keys(attributes);
const funcBody = attributeNames.map((attributeName) => {
return `attributes.${attributeName}[index],`;
}).join('\n');
const output = eval(`
attributes[attributeNames[0]].reduce((acc, value, index) => {
acc = acc.concat(${funcBody});
return acc;
}, []);
`);
console.log('\'output\' from code in the question: ' + JSON.stringify(output));
var output1 = [];
var n = attributes[ Object.keys(attributes)[0] ].length;
for (let col=0; col<n; col++){
for (let row in attributes){
if (Array.isArray(attributes[row][col]))
output1.push(...attributes[row][col])
else
output1.push(attributes[row][col]);
}
}
console.log('\'output1\' from column traversal: ' + JSON.stringify(output1));
I don't see where you needed nested loops. It appears to be quite straightforward:
const { AO: {length}, AO, jointId, paletteIdx, position, normal } = attributes;
const output = []; // test whether using `new Array(length * 9);` is better
for (let i=0, j=0; i<length; i++) {
output[j++] = AO[i];
output[j++] = jointId[i];
output[j++] = PaletteIdx[i];
output[j++] = position[i][0];
output[j++] = position[i][1];
output[j++] = position[i][2];
output[j++] = normal[i][0];
output[j++] = normal[i][1];
output[j++] = normal[i][2];
}
I can't imagine anything being faster. Since you are not using previously-unknown properties in the code, I don't think dynamic code generation would be of any help here.

Add items to an array skipping duplicates

I want to add items to an array skipping the duplicates. However for some reason only one item is being added and the second item is not being added. Here is my code.
var add = ['email1#gmail.com', 'email2#gmail.com', 'email1#gmail.com'];
var main_messages = []
var from
function findMessages(messageList) {
return messageList = from;
}
add.map(function(map){
from = map
if(main_messages.find(findMessages) === undefined){
main_messages.push(map)
}
});
console.log(main_messages)
So the expected output should be
['email1#gmail.com', 'email2#gmail.com']
But the output I'm getting in this code is only
['email1#gmail.com']
What am I doing wrong and how can I fix this problem?
Looks like you're missing a = in your return statement of findMessages, so you're basically setting from to messageList instead of comparing. Here's the fixed code
var add = ['email1#gmail.com', 'email2#gmail.com', 'email1#gmail.com'];
var main_messages = []
var from
function findMessages(messageList) {
return messageList === from;
}
add.map(function(map){
from = map
if(main_messages.find(findMessages) === undefined){
main_messages.push(map)
}
});
console.log(main_messages)
Consider using the JavaScript 1.6 / ECMAScript 5 native filter method of an Array in the following way:
var add = ['email1#gmail.com', 'email2#gmail.com', 'email1#gmail.com'];
var main_messages = add.filter(function(v, i, a) {return a.indexOf(v) === i;});
Another solution that should offer better performance O(x) would be to use array.reduce:
main_messages = Object.keys(add.reduce(function (p,c) {return (p[c] = true,p);},{}));
Both solutions will result in messages containing:
["email1#gmail.com", "email2#gmail.com"]
In case you need support for Browsers that don't have this implemented, as always there is a pollyfill offered by Mozilla (see bottom of page)
i think your error in below code
function findMessages(messageList) {
return messageList = from;
}
here i think you return to its parent so it is showing one vale.
for this you need to store messageList = from in a var, then return that variable.
var x = messageList;
return x;
You could implement a uniq function. Which is a specialised form of filter.
var add = ['email1#gmail.com', 'email2#gmail.com', 'email1#gmail.com'];
var main_messages = uniq(add);
function uniq(arr) {
var result = [];
for (var i = 0; i < arr.length; i++) {
if (result.indexOf(arr[i]) === -1) {
result.push(arr[i]);
}
}
return result;
}
console.log(main_messages)
On the other hand, map will always return an array of the same size, unless of course you muck about with assignments, etc.
map passes each element of an array to a callback function you use to modify the individual element without touching the actual array.
Think of it as 1 in 1 out, and so on, but you get the chance to change what is in the array, not how many things are in there. The idea is that there that the array resulting from map has the same length of the input array, but different content.
Methods that can result in an array of different size are filter and reduce for instance.
So being super-terse you could also do this:
var add = ['email1#gmail.com', 'email2#gmail.com', 'email1#gmail.com'];
var main_messages = add.filter( (el, idx, input) => input.indexOf(el) === idx );
console.log(main_messages)
You can use indexOf function in order to check the duplicate. You can try below way to add items to your array without duplicates.
var add = ['email1#gmail.com', 'email2#gmail.com', 'email1#gmail.com'];
var main_messages = []
add.map(function(map){
if(main_messages.indexOf(map) == -1){
main_messages.push(map)
}
});
console.log(main_messages);
Here is an easy answer: https://stackoverflow.com/a/18328062/5228251
Why do it the hard way, it can be done more easily using javascript filter function which is specifically for this kind of operations:
var add = ['email1#gmail.com', 'email2#gmail.com', 'email1#gmail.com'];
var main_messages = []
main_messages = add.filter( function( item, index, inputArray ) {
return inputArray.indexOf(item) == index;
});
------------------------
Output: ['email1#gmail.com', 'email2#gmail.com']
Depending on your needs, using a Set instead of an array may be what you are looking for:
The Set object lets you store unique values of any type, whether
primitive values or object references.
var add = ['email1#gmail.com', 'email1#gmail.com', 'email2#gmail.com', 'email1#gmail.com'];
// Init from an iterable.
var main_messages = new Set(add);
// Add a new email (not previously in the set).
main_messages.add('email3#gmail.com');
// Try to add an existing email, does nothing.
main_messages.add('email1#gmail.com');
console.log('main_messages:')
main_messages.forEach(msg => console.log('-', msg));
Of course, this option is only viable if you keep the data stored in the Set. It would be quite inefficient to convert it into an array after each insertion.
Set is an ES2015 feature. You may want to check the compatibility table and consider using a polyfill if needed.

How to split a URL string with parameters into an array using JavaScript

I'm trying to break up a string like this one:
fname=bill&mname=&lname=jones&addr1=This%20House&...
I want to end up with an array indexed like this
myarray[0][0] = fname
myarray[0][1] = bill
myarray[1][0] = mname
myarray[1][1] =
myarray[2][0] = lname
myarray[2][1] = jones
myarray[3][0] = addr
myarray[3][1] = This House
The url is quite a bit longer than the example. This is what I've tried:
var
fArray = [],
nv = [],
myarray = [];
fArray = fields.split('&');
// split it into fArray[i]['name']="value"
for (i=0; i < fArray.length; i++) {
nv = fArray[i].split('=');
myarray.push(nv[0],nv[1]);
nv.length = 0;
}
The final product is intended to be in 'myarray' and it is, except that I'm getting a one dimensional array instead of a 2 dimensional one.
The next process is intended to search for (for example) 'lname' and returning the index of it, so that if it returned '3' I can then access the actual last name with myarray[3][1].
Does this make sense or am I over complicating things?
Your line myarray.push(nv[0],nv[1]); pushes two elements to the array myarray, not a single cell with two elements as you expect (ref: array.push). What you want is myarray.push( [nv[0],nv[1]] ) (note the brackets), or myarray.push(nv.slice(0, 2)) (ref: array.slice).
To simplify your code, may I suggest using Array.map:
var q = "foo=bar&baz=quux&lorem=ipsum";
// PS. If you're parsing from a-tag nodes, they have a property
// node.search which contains the query string, but note that
// it has a leading ? so you want node.search.substr(1)
var vars = q.split("&").map(function (kv) {
return kv.split("=", 2);
});
For searching, I would suggest using array.filter:
var srchkey = "foo";
var matches = vars.filter(function (v) { return v[0] === srchkey; });
NB. array.filter will always return an array. If you always want just a single value, you could use array.some or a bespoke searching algorithm.
for (var i = 0; i < fArray.length; i++) {
nv = fArray[i].split('=');
myarray.push([nv[0],nv[1]]);
}
nv.length = 0; is not required, since you're setting nv in each iteration of the for loop.
Also, use var i in the for-loop, otherwise, you're using / assigning a global variable i, that's asking for interference.

Randomize children and reassign as children of separate node in Javascript

In prepping the objects for a game I'm making in javscript, I'm reading in a JSON object, deckData, and appending each as a child of this.discard. I'm then scheduling a job that checks to see if this.deck is empty. If it is, then the function should shuffle the array of cards listed as children of this.discard and then assign them as children of this.deck.
The whole process seems to work fairly smoothly except for the key line where I try to assign the newly shuffled array over:
this.deck.children_ = this.shuffle(this.discard.children_);
I'm looking for a solution that will succesfully append all elements that were children of this.discard as children of this.deck. And I realize I'm not yet emptying the array from this.discard yet either, but one step at a time. Full code snippet as follows:
sideboard = function(game) {
this.discard = new lime.Layer();
this.appendChild(this.discard);
for (var key in deckData) {
var cardData = deckData[key];
this.addCard(cardData);
};
this.mythosDeck = new lime.Layer();
this.appendChild(this.mythosDeck);
lime.scheduleManager.schedule(this.deckShuffler, this);
};
sideboard.prototype.deckShuffler = function() {
if (this.deck.children_.length < 1) {
this.deck.children_ = this.shuffle(this.discard.children_);
}
};
sideboard.prototype.shuffle = function(array) {
var tmp, current, top = array.length;
if(top) while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
};
Don't you just want to concatenate the two arrays and then reassign ? For example:
this.deck.children_ = this.deck.children_.concat(this.shuffle(this.discard.children_));

Categories