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 条代码规则(甚至还没有完成)。

4

3 回答 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());
于 2013-05-07T21:06:31.433 回答
0

我不会从头开始编写代码,而是使用可用的丰富库之一,例如下划线

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

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

这只是一点点,但如果这是你的意思,那么剩下的就很简单了。

于 2013-05-07T20:42:55.253 回答
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));

该算法只是从 List 中选择随机 N 个元素的答案chooseR中的一个过滤器改编。显然,是愚蠢的,但我只是保留它来展示方法的原理。chooseR(1)

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

于 2013-05-07T22:15:07.273 回答