【问题标题】:Efficiently store / compress an array of integers in Ruby?在 Ruby 中有效地存储/压缩整数数组?
【发布时间】:2013-04-04 01:57:06
【问题描述】:

我有一个唯一随机整数的排序数组,其值为 1

编辑:数组的大小最多为 1,000,000,000。

【问题讨论】:

  • 你有十亿个随机整数?还是数组大小为千兆字节?
  • 像@ctide 一样,我也对这个问题感到困惑。大小为 N...a[i] = i 的数组中唯一随机整数的排序数组,范围为 1 到 N,因此您可以只使用函数def a(i); return i; end?
  • 您是否有机会对数据提供更多约束?一个从 4 到 10 亿个完全随机整数的排序数组是一个相当大的压缩挑战。它们是真正随机的,还是以某种方式受到限制?例如,如果排序数组中的下一项总是在前一项的 256 以内,您可以只使用一个字节来存储 offset 。 . .
  • 我同意。对于非稀疏数组、稀疏数组和一万亿有序整数的全餐交易,您有以下解决方案。在某些情况下,没有一种解决方案不会在尺寸上爆炸。

标签: ruby algorithm integer


【解决方案1】:

使用narray 在 Ruby 中高效处理大型数值数组。

它更快,并且使用更少的内存。 http://narray.rubyforge.org/

至于DB存储部分。可以将编组添加到narray(默认情况下没有):

# This adds support for Marshal to NArray - found it at: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/194510
class NArray
  def _dump *ignored
    Marshal.dump :typecode => typecode, :shape => shape, :data => to_s
  end
  def self._load buf
    h = Marshal.load buf
    typecode = h[:typecode]
    shape = h[:shape]
    data = h[:data]
    to_na data, typecode, *shape
  end
end

。 . .这将非常有效,无需您编写特定代码。

如果数字是完全随机的,那么您可以通过压缩实现的效果将受到限制。真正的随机数据几乎是不可压缩的。

如果您对数字的排列方式有一个良好的约束模型,那么您可以利用这方面的知识来创建更好的压缩比。建议使用Range 的帖子就是一个极端的例子,但当然只有在结构非常简单的情况下才有效。

如果结构或多或少是任意的,只需整理数据并对其应用现成的压缩算法,例如zlib

编辑:项目已排序的事实有助于更好地压缩。它还为narray 打勾 - 它比您使用 Ruby Array 手动执行的任何操作都更快地对数字进行排序

示例代码:

require 'narray'
require 'zlib'

# Ten thousand integers . . .
n = NArray.int(10000).random(100000).sort

# Compressed . . .
stored = Zlib::Deflate.deflate( Marshal.dump(n), 9 )

stored.length

 => 14297

这还不错,每个数字 1.5 字节(实际压缩率会有很大差异,但使用这种技术通常会看到每个数字不到 4 字节)

【讨论】:

  • 不错!但是您的示例假设一个非稀疏数组。 NArray 不支持稀疏数组,因此存储索引为 1 和 900,000,000 的二元数组会占用大量空间。
  • OP 没有要求稀疏数组 AFAICT。事实上,鉴于数组已排序,对我来说似乎不太可能。但是,目前还不是 100% 清楚所要求的内容。
  • 是的。这听起来像是你在课堂上提出的问题之一,让他们意识到每个解决方案都有权衡。每次提出建议,老师都会添加一个炸毁解决方案的条件。可以很有趣!
【解决方案2】:

1..1,000,000,000 可以保存在 32 位整数中。如果数组是稀疏的,一个合理的编码是将每个有效元素表示为 2 个 32 位整数,一个是元素值,另一个是元素索引。数组中的每个有效元素都需要 64 位/2 个整数,再加上 32 位/一个整数来存储数组中有效元素的数量。

【讨论】:

  • +1 表示简单的方法备用,尽管 OP 似乎希望允许很大范围的可能性。
【解决方案3】:

您在 1..1e9 范围内有 1e9 个随机唯一整数,按排序顺序排列。这意味着您恰好拥有该范围内的每个整数之一。这是使用 ruby​​ 进行的最佳压缩:

存储这个:

"(1..10**9).to_a"

然后读回来并eval它。

【讨论】:

  • 数组最多 10亿。
  • @ZacharyBurt 编辑历史显示最多在我的翻转答案后添加了三个小时。事实是,这是一个非常糟糕的问题,有太多模糊的规范和约束,没有任何关于目的的暗示。弄清楚如何说出你真正的问题是什么,然后再试一次。
【解决方案4】:

您没有提及数据集的大小。数据需要多随机访问?使用位域压缩它可能会起作用,但是您会浪费时间解压缩数据,更不用说 Ruby 在处理此类数据时不如 C 高效。除非空间是一个主要问题,否则我会将其作为数据库存储在具有单个整数字段的表中。

【讨论】:

  • 已更新尺寸。不需要随机访问。
  • 如果它们被排序,并且有 10 亿个项目,在 1 到 10 亿的范围内,这是否意味着它只有 1.1 亿?为什么还要存储它?
猜你喜欢
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-18
  • 2016-12-26
  • 1970-01-01
相关资源
最近更新 更多