从阵列中均匀选择N个元素

时间:2010-03-15 23:57:23

标签: algorithm

我需要均匀从数组中选择 n 元素。我想最好的解释方法就是举例。

说我有:

数组[0,1,2,3,4]我需要选择3个数字.. 0,2,4。

当然,如果数组长度< = n ,我只需要返回整个数组。

我很确定有一个定义的算法,一直在尝试搜索,我看了算法简介但找不到满足我需求的东西(可能忽略了它) )

我遇到的问题是我无法找到一种方法将其扩展到任何数组[p..q],选择N个均匀元素。

注意:我不能只从上面的例子中选择偶数元素。

其他一些例子;

数组[0,1,2,3,4,5,6],3个元素;我需要得到0,3,6
数组[0,1,2,3,4,5],3个元素;我需要得到0,2或3和5

编辑:

更多例子:
数组[0,1,2],2元:0,2
数组[0,1,2,3,4,5,6,7],5元:0,2,3或4,5,7

是的,我想永远包括第一个和最后一个元素。

编辑2:

我在想的是......第一个+最后一个元素,然后使用中值继续工作。虽然我在试图这样做时感到困惑/困惑。

我会看看你发布的算法。谢谢!

编辑3:

这是使用PHP的 incrediman 解决方案的加强版本。也可以使用关联数组,同时保留键。

<?php

/**
 * Selects $x elements (evenly distributed across $set) from $set
 *
 * @param $set array : array set to select from
 * @param $x int     : number of elements to select. positive integer
 *
 * @return array|bool : selected set, bool false on failure
 */
///FIXME when $x = 1 .. return median .. right now throws a warning, division by zero

function select ($set, $x) {
    //check params
    if (!is_array($set) || !is_int($x) || $x < 1)
        return false;

    $n = count($set);

    if ($n <= $x)
        return $set;

    $selected = array ();
    $step     = ($n - 1) / ($x - 1);
    $keys     = array_keys  ($set);
    $values   = array_values($set);

    for ($i=0; $i<$x; $i++) {
        $selected[$keys[round($step*$i)]] = $values[round($step*$i)];
    }

    return $selected;
}

?>

你可以实现一个Iterator,但我不需要那么做。

5 个答案:

答案 0 :(得分:14)

享受! (伪代码):

function Algorithm(int N,array A)
    float step=(A.size-1)/(N-1)       //set step size

    array R                           //declare return array

    for (int i=0, i<N, i++)
        R.push(A[round(step*i)])  //push each element of a position which is a
                                      //multiple of step to R

    return R

这里最容易犯的错误可能是将step转换为整数或在开头将其舍入。但是,为了确保提取正确的元素,您必须将step声明为浮点数,舍入倍数step 正在迭代数组。

php中的测试示例:

<?

    function Algorithm($N,$A){

        $step=(sizeof($A)-1)/($N-1);
        for ($i=0;$i<$N;$i++)
            echo $A[round($step*$i)]." ";
        echo "\n";
    }

    //some of your test cases:
    Algorithm(3,array(1,2,3));
    Algorithm(5,array(0,1,2,3,4,5,6,7));
    Algorithm(2,array(0,1,2));
    Algorithm(3,array(0,1,2,3,4,5,6));
?>

Outputs:
1 2 3 
0 2 4 5 7 
0 2 
0 3 6 

(您可以在此处查看您的测试用例并尝试新的测试用例:http://codepad.org/2eZp98eD

答案 1 :(得分:2)

n+1为您想要的元素数量,已经限定为数组的长度。

然后,您希望元素位于数组末尾的索引0/n1/n,...,n/n

m+1为数组的长度。那么你的索引是round(m*i/n)(用浮点完成除法)。

答案 2 :(得分:1)

您的步长为(ArraySize-1)/(N-1) 只需将步长添加到浮点累加器,并将累加器四舍五入以获得数组索引。重复直到累加器&gt;数组大小。

答案 3 :(得分:1)

您希望在列表中包含第一个和最后一个元素。

如果要从N个项目列表中提取X项目,步长将为(N-1)/(X-1)。当你拉出每一个时,你想要的只是圆形。

答案 4 :(得分:0)

基于@ Rex 的答案。 伪代码!甚至有人可能会说这是 JS

    /// Selects |evenly spaced| elements from any given array. Handles all the edge cases.
    function select(array: [Int], selectionCount: Int) {

      let iterationCount = array.length - 1;           // Number of iterations
      let expectedToBeSelected = selectionCount - 1;   // Number of elements to be selected
      let resultsArray: [Int] = [];                    // Result Array

      if (selectionCount < 1 || selectionCount > array.length) {
        console.log("Invalid selection count!");
        return resultsArray;
      }
      var i;
      for (i in array) {
        if (selectionCount == 1) {
          resultsArray.push(array[i]);
          break;
        }
        let selectedSoFar = Math.round(iterationCount * i / expectedToBeSelected);
        if (selectedSoFar < array.length) {
          resultsArray.push(array[selectedSoFar]);
        } else {
          break; // If selectedSoFar is greater than the length then do not proceed further.
        }
      }
      return resultsArray;
    }