Reputation: 583
I've got a JSON objects array, from which I want to get a couple of random values. I did wrote some code myself, and it works in the end, but it's to ugly to even show.
So that's why I started this question. What should be good/nice ways to code the following situation?
We've got an JSON array like this: (it's longer actually, but just a couple as example)
"features" : [
{
"attributes" : {
"OBJECTID" : 6,
"Type" : "Gebied"
}
},
{
"attributes" : {
"OBJECTID" : 70,
"Type" : "Water"
}
},
{
"attributes" : {
"OBJECTID" : 80,
"Type" : "Water"
}
},
{
"attributes" : {
"OBJECTID" : 91,
"Type" : "Land"
}
},
{
"attributes" : {
"OBJECTID" : 66,
"Type" : "Gebied"
}
},
{
"attributes" : {
"OBJECTID" : 78,
"Type" : "Land"
}
}
]
From that array we want to create a new simple array, which contains, for example:
"type" = "Gebied"
"Type" = "Land"
Actually the number of features to select, which in this example are 1 and 2, can differ (up to 20 for one single type).
And most importantly, those features should be selected random.
I'm curious which approaches you guys would take and hopefully it helps to create a real nice block of code to do this, instead of the almost 100 rules of code I used now (and not even finished).
Upvotes: 3
Views: 728
Reputation: 76700
Here is more of a functional approach to the problem, which has the advantage that it sticks to the DRY principle and yields quite readable and reusable code. Basically, a pair of filters does all the work:
function isType(t) { // filter by Type
return function (el) {
return el.attributes.Type === t;
}
}
function chooseR(r) { // filter for choosing r of length
var found = 0;
return function (el, idx, arr) {
// calculate probability to keep [# needed / # left]
var keep = Math.random() < (r - found) / (arr.length - idx);
// increment if keeping
keep && found++;
return keep;
}
}
var myGebied = features.filter(isType('Gebied')).filter(chooseR(2)),
myLand = features.filter(isType('Land')).filter(chooseR(1));
The chooseR
algorithm is just a filter adaptation of the one in the answer to Select a random N elements from List. Obviously, chooseR(1)
is stupid, but I just kept it to show the principle of the approach.
If you don't care about IE8, Array.prototype.filter
is standard ES5 spec (see browser support). Otherwise, make sure to pick up a shim for that somewhere (the MDN page linked to has one at the bottom).
Upvotes: 0
Reputation: 973
Not sure this is what you want, if not, I'll just delete it.. but here it goes:
var gebied = 0;
var id = new Array();
for(var i = 0; i < features.length; i++)
{
if(features[i].attributes.Type == 'Gebied')
{
// saves the gebied instance +1
id[gebied] = features[i].attributes.OBJECTID;
gebied++;
}
}
// pick random 2 from gebied array
var id1;
var id2;
var idListLength = id.length;
id1 = id[Math.floor(Math.random() * idListLength)];
if (idListLength > 1) {
do {
id2 = id[Math.floor(Math.random() * idListLength)];
} while(id1 == id2);
}
// if it's just one random pick from array
var id1 = id[Math.floor(Math.random() * id.length)];
UPDATE
To have an input given number determine the number of random ids to pick:
function getRandomArrayElements(arr, count) {
var randoms = [], clone = arr.slice(0);
for (var i = 0, index; i < count; ++i) {
index = Math.floor(Math.random() * clone.length);
randoms.push(clone[index]);
clone[index] = clone.pop();
}
return randoms;
}
function pickRandom(count)
{
var gebied = 0;
var id = new Array();
for(var i = 0; i < features.length; i++)
{
if(features[i].attributes.Type == 'Gebied')
{
// saves the gebied instance +1
id[gebied] = features[i].attributes.OBJECTID;
gebied++;
}
}
return getRandomArrayElements(id, count);
}
Example:
pickRandom($('#random').val());
Upvotes: 1
Reputation: 31560
I would not code it from scratch but use one of the rich libraries available, like underscore:
var gebied = _.filter(features, function(f) {
return f.attributes.type === 'Gebied';
});
var result = [];
result.push(gebied[_.random(0, gebied,length)])
This is just one bit, but if this is what you mean then the rest is straightforward.
Upvotes: 0