从文件中选择100个随机行,其中100万个不能读入内存

时间:2016-02-28 08:14:18

标签: java algorithm file inputstream

实际上,这个问题被问了一个采访,我不知道确切的答案,你能详细解释一下吗?

  

如何从100万个文件中选择100个随机行   行呢?无法将文件读入内存。

3 个答案:

答案 0 :(得分:4)

通常情况下,在这种情况下,您提前不知道输入文件中的项目数(并且您希望避免要求对数据进行两次传递,以检查可用项目的数量第一)。在这种情况下,@ radoh和其他人提出的解决方案,你将创建索引以供选择,将无法正常工作。

在这种情况下,您可以使用reservoir sampling:您只需要知道要选择的项目数(k如下)并迭代输入数据({{1} })。下面是从维基百科中获取的伪代码,我将把它转换为一种有效的Java方法(该方法通常看起来像S[1..n]):

List<X> sample(Stream<X> data, int k)

请注意,虽然代码明确提到/* S has items to sample, R will contain the result */ ReservoirSample(S[1..n], R[1..k]) // fill the reservoir array for i = 1 to k R[i] := S[i] // replace elements with gradually decreasing probability for i = k+1 to n j := random(1, i) // important: inclusive range if j <= k R[j] := S[i] (即输入项的数量),但您不需要在计算之前知道该值。您可以简单地遍历nIterator(表示您的文件中的行),只需要将结果数组或集合Stream保留在内存中。您甚至可以对连续流进行采样,并且在每个时间点(至少,您已经看到R样本的时候),您随机k选择的项目。

答案 1 :(得分:2)

生成100个随机(唯一)数字(范围从0..1000000-1)到列表中,然后浏览文件,读取列表中带有索引的行。理想情况下,数字列表应为Set

伪代码:

int i = 0;
List<String> myLines = new ArrayList();
while (fileScanner.hasNext()) {
  String line = fileScanner.nextLine();  
  if (myRandomNumbers.contains(i)) {
    myLines.add(line);
  }
  i++;
}

答案 2 :(得分:1)

这是一种非常有效的方法:

function rotate ( center, distance ) {
    var axis = center.axis;
    center.model.rotateOnAxis ( axis, distance );
    applyStatesToMatrixDirectly ( center.model );

    for ( var stickerIndex in center.stickers ) {
        center.stickers[stickerIndex].rotateOnAxis ( axis, distance  );
        applyStatesToMatrixDirectly ( center.stickers[stickerIndex] );
    }

    for ( var childIndex in center.children ) {
        center.children[childIndex].model.rotateOnAxis ( axis, distance );
        applyStatesToMatrixDirectly ( center.children[childIndex].model );

        for ( var childStickerIndex in center.children[childIndex].stickers ) {
            center.children[childIndex].stickers[childStickerIndex].rotateOnAxis ( axis, distance );
            applyStatesToMatrixDirectly ( center.children[childIndex].stickers[childStickerIndex] );
        }
    }
}

function applyStatesToMatrixDirectly ( model ) {
    model.updateMatrix();
    model.geometry.applyMatrix( model.matrix );
    model.position.set( 0, 0, 0 );
    model.rotation.set( 0, 0, 0 );
    model.scale.set( 1, 1, 1 )
    model.updateMatrix();
}

我有一段时间没用Java编写代码,因此您可能希望将其视为伪代码。

该算法基于以下事实:任何给定行的概率(假设我们在总共n行中均匀地选择k个不同的行)将以概率k / n包含在集合中。这是从

开始的

1)选择k个不同行(n行中)的数字集合(n,k),

2)选择包含特定行的k个不同行(n行中)的集合数(n-1,k-1)和

3)选择(n-1,k-1)/选择(n,k)= k / n

请注意,此处的k和n分别对应代码中的Iterator<String> linesIter = ... List<String> selectedLines = new ArrayList(); Random rng = new Random(seed); int linesStillNeeded = 100; int linesRemaining = 1000000; while (linesStillNeeded > 0) { String line = linesIter.next(); linesRemaining--; if (rng.nextInt(linesRemaining) < linesStillNeeded) { selectedLines.add(line); linesStillNeeded--; } } linesStillNeeded