I have two 1D arrays and I want to fill them with 10 unique random x,y values in Processing.
For example:
x y
- -
3, 9
2, 4
6, 2
7, 5
My arrays are:
Table1 for the X values and
Table2 for the Y values.
My issue is if the number 3,9 exists already I don't want 9,3 to be stored in the arrays.
I can identify when x,y value (or y,x) already exists but once I replace it I cannot check if the new generated random number exist in the previous indexes.
This is what I have tried so far. However if 3 values aldready exists, the arrays Table1 and Table2 will store only 7 values instead of 10.
for (int i=0; i<10; i++) {
x=(int)random(6);
y=(int)random(6);
if ((Table1[i] != x && Table2[i] != y) || (Table1[i] != y && Table2[i] != x))
{
Table1[i] = x;
Table2[i] = y;
}
Any ideas how to control that?
I can think about only two ways of achieving it, and none is ideal.
Check if the numbers you generated already exists, and if it's the case, generate anothers until you get a unique combination. It could be expensive with a small range of possibilities, because it's random, and if you're very unlucky you could even end in an infinite loop...
Create an array containing every possible combination. Then, instead of generating random numbers, you'll generate a random index into this array (an integer in [0;array.length[). After that, you'll have to remove the choosen combination from the array (that way it won't be available for the next loop), and the inverse of it (if you picked (9;3), you have to remove (9;3) AND (3;9)).
I have this code that might help you,
first declare your arrays :
var a = [];
var b = [];
then you can call a function that does everything for you
fill(a,b)
The definition of this function should be something like this :
function fill(a, b) {
var arr = [];
while(arr.length<10) {
var pair = randomPair();
if (arr.indexOf(pair.join(','))==-1 || arr.indexOf(pair.reverse().join(','))==-1) {
a.push(pair[0]);
b.push(pair[1]);
arr.push(pair.join(','));
}
}
}
then the defintion of other used function is :
function randomPair () {
return [ parseInt(Math.random()*7) , parseInt(Math.random()*7) ]
}
so, obviously, the randomPair function returns 2 values x and y. the fill function tests if the pair already exists or not in normal order or reversed order. if not it's added both a, and b which are references to your main arrays;
I see no other option as to walk to the whole arrays again to check if they contains your new generated value(s).
Related
This question already has answers here:
Fast stable sorting algorithm implementation in javascript
(16 answers)
Closed 6 years ago.
Here is my jsFiddle:
//Change this variable to change the number of players sorted
var numberOfPlayers = 15;
var teams = [];
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for(var a=0; a<numberOfPlayers; a++){
updateStandings();
teams.push(new Team(alphabet.charAt(a)));
}
console.log("Teams:");
for(var x=0; x<teams.length; x++){
console.log(teams[x].name);
}
//Functions and such
function updateStandings(){
teams.sort(function(a, b) {
if(a.score == b.score){
if(a.tiebreak == b.tiebreak){
return teams.indexOf(a)-teams.indexOf(b);
}else{
return b.tiebreak-a.tiebreak;
}
}else{
return b.score-a.score;
}
});
}
function Team(name){
this.name = name;
this.score = 0;
this.tiebreak = 0;
}
I assumed the problem was that javascript sorting was unstable, and changed my compare function, but it still does not work.
The generic approach to stable sorting in JS is as follows:
function stable_sort(array, sortfunc) {
function _sortfunc(a, b) { return sortfunc(array[a], array[b]) || a - b; }
return array.map((e, i) => i) . sort(_sortfunc) . map(i => array[i]);
}
What this actually does is to sort a list of indices. Then it maps the sorted list of indices back to the original array. The sort function is rewritten to compare the values in the array at those indices, and if they are equal then fall back to a comparison of indices themselves.
This approach avoids the problem in your code which is that it is doing indexOf look-ups into an array which is the middle of being sorted.
This question could be informative.
According to the documentation, sort method is not required to be stable: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort In some browsers it is stable, in some not.
You do need to change the compare function, but not in the way that you tried. The reason is that you compare
return teams.indexOf(a)-teams.indexOf(b);
in the current array. It means that if the order of a and b has changed on the previous steps, your sorting routine will preserve this new order, not the one that these elements had in the beginning.
There are different ways to solve it. For example, you can create a copy of the array before sorting and execute indexOf on this copy. It will preserve the order that elements had had before sorting started.
But if your know that order in advance, you can also use this knowledge. For example, if before sorting the teams was sorted by their names, you can compare names as strings instead of positions in the array, it would be much more efficient than the first option.
Because JS' sorting is typically unstable. From ยง22.1.3.24 of the spec:
The elements of this array are sorted. The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order).
Your teams are created with identical properties except their name, so the line actually performing the sort is:
return teams.indexOf(a)-teams.indexOf(b);
Because you're calling indexOf, it searches for the item (and its index) each repetition of the sort. Sorting mutates the array (from MDN: it "sorts the elements of an array in place and returns the array").
You are searching for the item within the same array you are sorting, so the index may change on each iteration. Done correctly (relatively speaking), you could produce a never-ending sort with that.
For example:
const data = [1, 3, 2, 4];
let reps = 0;
data.sort((a, b) => {
console.log(data);
const ia = data.indexOf(a), ib = data.indexOf(b);
if (ia === ib || reps > 50) {
return 0;
} else if (ia < ib) {
return 1;
} else if (ib < ia) {
return -1;
}
});
I have two arrays, one with strings of large numbers and the other with the sums of the large numbers added together, is there any way where I can have the two arrays correspond with each other? Like to make location [2] in the first array correspond with the same location in the second array. More specifically, I originally establish the array of large numbers, and I've written a function that creates the second array giving me the sums of each numeral in the large numbers (ex. 123456789 in the first array would be 45 in the second array), but I need to be able to link the two arrays because the first array needs to work with any number of strings of numbers. (sorry if this is confusing; I'm just a little out of my depth on this.)
Here is the code I'm working on:
var theArray = ["585-777-7279", "922-901-8934", "112-211-4857", "994-934-9989"];
var plsWork = function() {
var theArrayTwo = theArray.join().replace(/-/g, "");
var theArrayThree = theArrayTwo.split(",").map(Number);
var phoneSum = theArrayThree.map(function (a) {
return Array.prototype.slice.call(a.toString()).map(Number).reduce(function(b,c) {
return b + c;
});
})
phoneSum.sort().reverse();
console.log(phoneSum);
};
Basically, I just want to know if there's a way that I can get the two arrays (the original and the one created in the function) to correspond. Ideally, I would like to be able to have it where I can show that the smallest sum corresponds with the number from the first array.
If you already have the two arrays, the best way to relate one to another would be to create an array of objects as suggested by #webdeb.
If instead you have the array of large numbers and then all you want is to create a second array that in each index contains the sum of all the digits of the number in the first array, than I would use the following code:
var large_numbers = [1234, 2345, 3456];
function sumDigits(number) {
var digitsArray = [],
string = number.toString(); // convert number to string
for (let i = 0; i < string.length; i++) {
// push the numbers to a temporary array so that
// I can sum them one by one later
digitsArray.push(parseInt(string[i], 10));
}
// return the sum of all the elements of the digitsArray
return tempArray.reduce(function(prev, curr) {
return prev + curr;
})
}
var sumsArray = large_numbers.map(sumDigits); // -> [10, 14, 18]
The sumsArray contains in the sum of all the digits of the number in the large numbers array in the same index.
I have a two-dimensional array in Google apps script that contains arrays of different lengths. I would like to set the values of the array in a spreadsheet. However, because the arrays inside it are different lengths, I receive an error that essentially says the range and the array height don't line up. I've listed an example of the structure of the array below.
I can make it work if I add empty values to each individual array so that they all match the length of the longest array. This seems like a workaround though. Is there another way that I can set the values of the two-dimensional array?
var array = [
[a],
[b,c],
[d,e],
[],
[f,g,h,i],
[],
[j,k],
]
No, you cannot. The dimensions must match.
What you can do if you have few "rows" with great length difference, is to set each row on it's own.
for( var i = 0; i < array.length; ++i )
sheet.getRange(i+1, 1, 1, array[i].length).setValues([array[i]]);
But that's just another workaround. But working on your array to make all lengths match and do a single setValues will probably perform better.
In case your real array has many rows, individual writes will be expensive. Redimensioning each row array is fairly straightforward due to the way js handles arrays. A pattern similar to one i use is:
function myFunction() {
var array = [
[1],
[2,2],
[3,5],
[],
[0,0,0,0],
[],
[0,0],
];
// get length of the longest row
var max = array
.slice(0)
.sort(function (a,b) {
return ( (a.length !== b.length) ? 1 : 0 );
})[0].length;
// arrays are zero indexed
var maxi = max-1;
// insert a pointer at max index if none exists
array = array
.map(function (a){
a[maxi] = a[maxi] || "";
return a;
});
Logger.log(array);
}
I have an array of objects which I need placed in a certain order, depending on some configuration data. I am having a problem with itterating through the array in the proper order. I thought that if I made the array, and then stepped through with a for loop, I would be able to execute the code correctly. It is working great except in one use case, in which I add the fourth item to the array and then go back to the third.
links[0] = foo
links[1] = bar
links[2] = foobar
links[3] = a_herring
links[4] = a_shrubery
order = [] //loaded from JSON, works has the numbers 1 2 3 or 4 as values
//in this case:
order[0] = 1
order[1] = 2
order[2] = 4
order[3] = false
order[4] = 3
for(x in order){
if(order[x]){
printOrder[order[x]]=links[x]
//remember that in this case order[0] would
}
This should give me an array that looks like this:
//var printOrder[undefined,foo,bar,a_shrubbery,foobar]
But when I try to itterate through the array:
for(x in printOrder){
printOrder[x].link.appendChild(printOrder[x].image)
printOrder[x].appendChild(printOrder[x].link)
printOrder[x].appendChild(printOrder[x].text)
document.getElementById("myDiv").appendChild(printOrder[x]);
}
I get foo, bar, foobar, a_shrubbery as the output instead.
I need to either sort this array by key value, or step through it in the correct order.
Iterating over the numerically-index properties of Array instances should always be done with a numeric index:
for (var x = 0; x < printOrder.length; ++x) {
// whatever with printOrder[x]
}
Using the "for ... in" form of the statement won't get you predictable ordering, as you've seen, and it can have other weird effects too (particularly when you mix in JavaScript frameworks or tool libraries or whatever). It's used for iterating through the property names of an object, and it doesn't treat Array instances specially.
You need to create a function for finding values in an array like this:
Array.prototype.indexOf = function(value)
{
var i = this.length;
while ( i-- )
{
if ( this[ i ] == value ) return i;
}
return -1;
};
You can then use it like this:
//NOTICE: We're looping through LINKS not ORDER
for ( var i = 0; i < links.length; i++ )
{
var index = order.indexOf( i );
//It's in the order array
if ( index != -1 ) printOrder[ i ] = links[ i ];
}
REMEMBER: You need to make sure the values returned in json are integers. If they're strings, then you'll need to convert the integers to string when passed to indexOf.
The function you have in your question works as you suggest it should.
http://jsfiddle.net/NRP2D/8/ .
Clearly in this simplified case you have removed whatever error you are making in the real case.
Imagine the following situation:
var array = new Array ( [0,0,0,0], [0,0,1,0], [0,0,0,0] );
var x = 0; var y = 0;
if(array[y][x]) {
// x and y can be any integer
// code should execute only for array[1][2]
}
When x and y refer to an item in the array that exists, everything is fine. Otherwise, the script terminates. Obviously this is not the behaviour I want - is it possible to reference Javascript multidimensional arrays safely?
You need to check that the referenced property exists at each level of the array:
if(array[y] && array[y][x]) {
// x and y can be any integer
// code should execute only for array[2][1]
}
You can use the in keyword to check whether there is a y-th element of the array and whether that element has a x-th element as preliminary checks:
if (y in array && x in array[y] && array[y][x]) {...
Javascript arrays aren't so much multidimensional as they are compound/jagged. You can also use Array.length, but that relies on the object being an array, which is part of what we're checking, so it complicates the check.
A bit more verbose than the other answers:
var array = [ [0,0,0,0], [0,0,1,0], [0,0,0,0] ];
var x = 0; var y = 0;
if(array.hasOwnProperty(y) && array[y].hasOwnProperty(x) && array[y][x] !== 0) {
// x and y can be any integer
// code should execute only for array[2][1]
}
...but this one is impervious to additions to Array.prototype.
Also, explicitly testing for equality with zero makes it more readable, IMHO. (Compensating for the reduced readability of the preceding conditions... :-P)