从jQuery数组中随机选择

3
我有一个JSON对象数组,我想从中获取一些随机值。我写了一些代码,最终它确实可以工作,但是太丑了,甚至不想展示。
因此,我发起了这个问题。应该如何编写以下情况的良好/美好的方式?
我们有一个像这样的JSON数组:(实际上更长,但只是几个例子)
"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"
      }
    }
]

我们希望从该数组中创建一个新的简单数组,其中包含:

  • 2个带有"type" = "Gebied"属性的要素
  • 1个带有"Type" = "Land"属性的要素

实际上,要选择的功能数量可以不同(在此示例中为1和2),最多可达20个单一类型的功能。

最重要的是,这些功能应该被随机选中。

我很想知道你们会采取哪些方法,并希望它能帮助创建一个真正好用的代码块来完成这个任务,而不是使用我现在几乎100行的代码规则(而且还没有完成)。

3个回答

1

不确定这是否是您想要的,如果不是,我将删除它...但是这就是:

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)];

更新

为了让输入的数字确定要选择多少个随机ID,请执行以下操作:

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);
}

例子:

pickRandom($('#random').val());

哦,伙计,我非常喜欢你的方法!谢谢。还有一件事:要选择的项目数量也是可变的。所以(基于输入框),有时我想选择3个“gebied”的实例,而另一次我想选择15个。我也在问题中加入了这个信息。所以我认为最后一部分需要进行一些修改。你有什么想法吗? - Dennis Hunink
我做了一些研究,这是针对你的情况的更新代码http://fiddle.jshell.net/XsYgy/1/...如果正确的话,我会添加到主要答案中。 - Fabi
就像在jsFiddle中一样,它绝对看起来是我想要实现的。所以如果您将其添加到您的答案中,那将非常好。我明天会进一步测试它,然后回复您,很可能会接受您的答案。对此我非常感激! - Dennis Hunink
如果你有另一个类型为feature的字段,你也可以很容易地添加它,我已经在fiddle中更新了它。 - Fabi

0

我不会从头开始编码,而是使用其中一个丰富的可用库,例如underscore

var gebied = _.filter(features, function(f) {
  return f.attributes.type === 'Gebied';
});

var result = [];
result.push(gebied[_.random(0, gebied,length)])

这只是一个比特,但如果这就是你的意思,那么其余部分就很简单了。


0

这里提供了一种更加功能性的方法来解决问题,它有一个优点,即遵循DRY原则并产生相当可读和可重用的代码。基本上,一对过滤器完成所有工作:

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));

chooseR算法只是从列表中选择随机N个元素的答案中的一个过滤器适应。显然,chooseR(1)是愚蠢的,但我只是为了展示这种方法的原理而保留它。

如果您不关心IE8,Array.prototype.filter是标准的ES5规范(请参见浏览器支持)。否则,请确保在某个地方获取该shim(链接到的MDN页面底部有一个)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接