Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在ruby中,对于2d数组,如何删除与一个值之外的另一行相匹配的行?_Arrays_Ruby - Fatal编程技术网

Arrays 在ruby中,对于2d数组,如何删除与一个值之外的另一行相匹配的行?

Arrays 在ruby中,对于2d数组,如何删除与一个值之外的另一行相匹配的行?,arrays,ruby,Arrays,Ruby,给定如下所示的数组: array = [[1, "a", 34], [1, "a", 72], [1, "b", 82], [2, "a", 72], [2, "b", 34], [2, "b", 32], [3, "a", 72], [3, "b", 82], [3, "b", 34], [4, "a", 93], [4, "b", 15]] 我想知道,如何使用ruby删除与另一行中的所有值相匹配的所有行,第一个值必须等于n-1。 这意味

给定如下所示的数组:

array = [[1, "a", 34], [1, "a", 72], [1, "b", 82],
         [2, "a", 72], [2, "b", 34], [2, "b", 32],
         [3, "a", 72], [3, "b", 82], [3, "b", 34],
         [4, "a", 93], [4, "b", 15]]
我想知道,如何使用ruby删除与另一行中的所有值相匹配的所有行,第一个值必须等于n-1。 这意味着[1,a,72]被删除,因为有一行[2,a,72],该行也将被删除,因为[3,a,72]存在。 [2,b,34]也将被删除,因为存在[3,b,34]

因此,脚本将返回以下数组:

array = [[1, "a", 34], [1, "b", 82],
         [2, "b", 32],
         [3, "a", 72], [3, "b", 82], [3, "b", 34],
         [4, "a", 93], [4, "b", 15]]

谢谢你的帮助

我会这样做:

array.delete_if do |item|
  a, b, c = item
  array.include? [a + 1, b, c]
end
这将遍历数组,对于每个项:

将数组分解为三个单独的变量:a、b和c。当您在自己的代码中使用这些名称时,您可能应该给出这些更具描述性的名称

使用递增的值重建数组,并检查数组中是否存在此新数组

如果是,请删除此项目


请注意,这会直接对数组进行变异,而不是返回修改过的副本。

我会这样做:

array.delete_if do |item|
  a, b, c = item
  array.include? [a + 1, b, c]
end
这将遍历数组,对于每个项:

将数组分解为三个单独的变量:a、b和c。当您在自己的代码中使用这些名称时,您可能应该给出这些更具描述性的名称

使用递增的值重建数组,并检查数组中是否存在此新数组

如果是,请删除此项目


请注意,此解决方案直接变异数组,而不是返回修改过的副本。

此解决方案的时间复杂度为On

代码

解释

prune返回缩减后的数组,但不修改其参数array。如果要替换数组,请写入

array = prune(array)
或将方法的最后一行更改为:

array.replace(array.values_at *keepers_idx.values.flatten(1).sort)
取决于需求

idx中的值是要保留的数组元素的索引,其最后2个元素由相应的键给出。例如,要保留的以[b,82]结尾的数组位于索引2和7处。还要注意,当arr=array时

由h=hash.new{| h,k | h[k]=[]}创建的空散列具有这样一个属性:如果h没有键k,比如k=['a',34],那么

这样我们就可以写作了

h[k] << 0
  #=> [0]
我们现在执行块计算

h.key?(rest)
  #=> {}.key(["a", 34]) => false
所以我们不执行h[rest].pop。继续

h[rest] << i 
  #=> h[["a", 34]] << 0 => [0] 
h #=> {["a", 34]=>[0]}
h[rest] << i
  #=> h[["a", 72]] << 3 => [3] 
h #=> {["a", 34]=>[0], ["a", 72]=>[3], ["b", 82]=>[2]}
经过一个类似的步骤

h=> {["a", 34]=>[0], ["a", 72]=>[1], ["b", 82]=>[2]}
现在情况即将改变

((n,*rest),i),h = enum.next
  #=> [[[2, "a", 72], 3], {["a", 34]=>[0], ["a", 72]=>[1], ["b", 82]=>[2]}]
n    #=> 2 
rest #=> ["a", 72] 
i    #=> 3 
h    #=> {["a", 34]=>[0], ["a", 72]=>[1], ["b", 82]=>[2]}  

h.key?(rest)
  #=> h.key?(["a", 72]) => true
n == arr[h[rest].last].first + 1
  #=> 2 == arr[h[["a", 72]].last].first + 1
  #=> 2 == arr[[1].last].first + 1
  #=> 2 == arr[1].first + 1
  #=> 2 == [1, "a", 72].first + 1 => true
所以我们执行

h[rest].pop     
  #=> h[["a", 72]].pop => 1
h #=> {["a", 34]=>[0], ["a", 72]=>[], ["b", 82]=>[2]}
继续

h[rest] << i 
  #=> h[["a", 34]] << 0 => [0] 
h #=> {["a", 34]=>[0]}
h[rest] << i
  #=> h[["a", 72]] << 3 => [3] 
h #=> {["a", 34]=>[0], ["a", 72]=>[3], ["b", 82]=>[2]}
最后,

  arr.values_at *(0..arr.size-1).to_a & keepers_idx.values.flatten

a = keepers_idx.values
  #=> [[0], [6], [2, 7], [8, 11], [5], [9], [10]] 
b = a.flatten
  #=> [0, 6, 2, 7, 8, 11, 5, 9, 10] 
c = arr.size.times.to_a
  #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 
d = c & b
  #=> [0, 2, 5, 6, 7, 8, 9, 10, 11]

arr.values_at *d
  #=> arr.values_at(0, 2, 5, 6, 7, 8, 9, 10, 11) 
  #=> [[1, "a", 34], [1, "b", 82], [2, "b", 32], [3, "a", 72], [3, "b", 82],
  #=>  [3, "b", 34], [4, "a", 93], [4, "b", 15], [5, "b", 34]] 
在计算c&b时,doc保证从原始数组[c]保留顺序

处理文件

显然,数组的元素包含在一个大文件中。让我们假设该文件对于上面给出的数组具有以下格式

s = array.map { |a| a.map(&:to_s).join(",") }.join("\n")
puts s
1,a,34
1,a,72
1,b,82
2,a,72
2,b,34
2,b,32
3,a,72
3,b,82
3,b,34
4,a,93
4,b,15
5,b,34
s可以有一个结尾的新行,这没关系。让我们将其写入文件

FName = 'temp'
File.write(FName, s)
  #=> 83
检查它:

s == File.read(FName)
  #=> true
该方法可以修改如下。通过文件进行两次扫描,逐行读取

第一个过程构造散列保持器。该散列类似于上面的idx,但值是修改的。keeper_idx的值是索引数组。keepers的值是形式为[i,n]的两个元素数组的数组,其中i是文件中该行的索引,n是从该行获得的第一个整数。例如,在索引2中考虑行1、B、82。然后将数组[2,1]追加到键[b,82]的值数组中,该值已初始化为空数组

第二次遍历文件时,在keepers给定的索引处提取行,保存在排序后的数组行中。我返回了一个提取行的数组,转换为三元素数组。如果由于内存不足而不允许这样做,请参阅结尾处的注释

def prune(fname)
  keepers =
    File.foreach(fname).
         with_index.
         with_object(Hash.new {|h,k| h[k]=[]}) do |(line,i),h|
           n, *rest = convert(line)
           h[rest].pop if h.key?(rest) && n == h[rest].last.last + 1
           h[rest] << [i,n]
         end
  keepers = keepers.values.flatten(1).map(&:first)
  keepers = (0..keepers.max).to_a & keepers
  next_line = keepers.shift
  File.foreach(fname).
       with_index.
       with_object([]) do |(line,i),a|
         if i == next_line
           a << convert(line)
           next_line = keepers.shift
           break a if keepers.nil?
         end
       end
end

def convert(line)
  a,b,c = line.chomp.split(',')
  [a.to_i, b, c.to_i]
end
注:

更换线路可能会更快 与

根据文件格式,当然可能需要修改convert。目前:
如果prune返回的数组太大而无法保存在内存中,则可以替换行a此解决方案的时间复杂度为On

代码

解释

prune返回缩减后的数组,但不修改其参数array。如果要替换数组,请写入

array = prune(array)
或将方法的最后一行更改为:

array.replace(array.values_at *keepers_idx.values.flatten(1).sort)
取决于需求

idx中的值是要保留的数组元素的索引,其最后2个元素由相应的键给出。例如,要保留的以[b,82]结尾的数组位于索引2和7处。还要注意,当arr=array时

由h=hash.new{| h,k | h[k]=[]}创建的空散列具有这样一个属性:如果h没有键k,比如k=['a',34],那么

这样我们就可以写作了

h[k] << 0
  #=> [0]
我们现在执行块计算

h.key?(rest)
  #=> {}.key(["a", 34]) => false
所以我们不执行h[rest].pop。继续

h[rest] << i 
  #=> h[["a", 34]] << 0 => [0] 
h #=> {["a", 34]=>[0]}
h[rest] << i
  #=> h[["a", 72]] << 3 => [3] 
h #=> {["a", 34]=>[0], ["a", 72]=>[3], ["b", 82]=>[2]}
经过一个类似的步骤

h=> {["a", 34]=>[0], ["a", 72]=>[1], ["b", 82]=>[2]}
现在情况即将改变

((n,*rest),i),h = enum.next
  #=> [[[2, "a", 72], 3], {["a", 34]=>[0], ["a", 72]=>[1], ["b", 82]=>[2]}]
n    #=> 2 
rest #=> ["a", 72] 
i    #=> 3 
h    #=> {["a", 34]=>[0], ["a", 72]=>[1], ["b", 82]=>[2]}  

h.key?(rest)
  #=> h.key?(["a", 72]) => true
n == arr[h[rest].last].first + 1
  #=> 2 == arr[h[["a", 72]].last].first + 1
  #=> 2 == arr[[1].last].first + 1
  #=> 2 == arr[1].first + 1
  #=> 2 == [1, "a", 72].first + 1 => true
所以我们执行

h[rest].pop     
  #=> h[["a", 72]].pop => 1
h #=> {["a", 34]=>[0], ["a", 72]=>[], ["b", 82]=>[2]}
继续

h[rest] << i 
  #=> h[["a", 34]] << 0 => [0] 
h #=> {["a", 34]=>[0]}
h[rest] << i
  #=> h[["a", 72]] << 3 => [3] 
h #=> {["a", 34]=>[0], ["a", 72]=>[3], ["b", 82]=>[2]}
最后,

  arr.values_at *(0..arr.size-1).to_a & keepers_idx.values.flatten

a = keepers_idx.values
  #=> [[0], [6], [2, 7], [8, 11], [5], [9], [10]] 
b = a.flatten
  #=> [0, 6, 2, 7, 8, 11, 5, 9, 10] 
c = arr.size.times.to_a
  #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 
d = c & b
  #=> [0, 2, 5, 6, 7, 8, 9, 10, 11]

arr.values_at *d
  #=> arr.values_at(0, 2, 5, 6, 7, 8, 9, 10, 11) 
  #=> [[1, "a", 34], [1, "b", 82], [2, "b", 32], [3, "a", 72], [3, "b", 82],
  #=>  [3, "b", 34], [4, "a", 93], [4, "b", 15], [5, "b", 34]] 
在 通过计算c&b,文档保证从原始数组[c]中保留顺序

处理文件

显然,数组的元素包含在一个大文件中。让我们假设该文件对于上面给出的数组具有以下格式

s = array.map { |a| a.map(&:to_s).join(",") }.join("\n")
puts s
1,a,34
1,a,72
1,b,82
2,a,72
2,b,34
2,b,32
3,a,72
3,b,82
3,b,34
4,a,93
4,b,15
5,b,34
s可以有一个结尾的新行,这没关系。让我们将其写入文件

FName = 'temp'
File.write(FName, s)
  #=> 83
检查它:

s == File.read(FName)
  #=> true
该方法可以修改如下。通过文件进行两次扫描,逐行读取

第一个过程构造散列保持器。该散列类似于上面的idx,但值是修改的。keeper_idx的值是索引数组。keepers的值是形式为[i,n]的两个元素数组的数组,其中i是文件中该行的索引,n是从该行获得的第一个整数。例如,在索引2中考虑行1、B、82。然后将数组[2,1]追加到键[b,82]的值数组中,该值已初始化为空数组

第二次遍历文件时,在keepers给定的索引处提取行,保存在排序后的数组行中。我返回了一个提取行的数组,转换为三元素数组。如果由于内存不足而不允许这样做,请参阅结尾处的注释

def prune(fname)
  keepers =
    File.foreach(fname).
         with_index.
         with_object(Hash.new {|h,k| h[k]=[]}) do |(line,i),h|
           n, *rest = convert(line)
           h[rest].pop if h.key?(rest) && n == h[rest].last.last + 1
           h[rest] << [i,n]
         end
  keepers = keepers.values.flatten(1).map(&:first)
  keepers = (0..keepers.max).to_a & keepers
  next_line = keepers.shift
  File.foreach(fname).
       with_index.
       with_object([]) do |(line,i),a|
         if i == next_line
           a << convert(line)
           next_line = keepers.shift
           break a if keepers.nil?
         end
       end
end

def convert(line)
  a,b,c = line.chomp.split(',')
  [a.to_i, b, c.to_i]
end
注:

更换线路可能会更快 与

根据文件格式,当然可能需要修改convert。目前:
如果prune返回的数组太大,无法保存在内存中,可以替换块参数中直接分配给a、b和c的行:array.delete_If{a、b、c | array.include?[a+1、b、c]}非常感谢您的回答,这正是我想要的!在定义a、b、c之前定义项目是否有原因?删除第二行并定义块参数a、b、cin不是更简单吗?@Dobby不客气!这样做可能会更容易,我刚刚忘记了这个功能。你可以直接在块参数中指定a、b和c:array。如果{a、b、c{array.include?[a+1、b、c]}删除{u,这正是我要找的!在定义a、b、c之前定义项目是否有原因?删除第二行并定义块参数a、b、cin不是更简单吗?@Dobby不客气!这可能会更容易做到,我刚刚忘记了这个功能。谢谢你的回答!我不熟悉时间复杂度,时间复杂度为On是否意味着它将比另一个建议的答案运行得更快或更慢?@Hildoby这将比我的答案运行得更快:我的答案在^2最坏情况下,而这是开启的。Hildoby,请参阅时间复杂度的解释。谢谢@CarySwoveland!这非常有效,而且确实比其他建议的解决方案快得多。但是,对于非常大的文件,我在这一行得到以下错误堆栈级别太深SystemStackError:arr.values_at*arr.size.times.to_a&keepers_idx.values.flatte,我如何解决这个问题?导致错误的文件有多大?另外,在一个问题文件中的所有元素[a,b,c]中,你知道我散列中的键的唯一数组[b,c]的数量吗?谢谢你的回答!我不熟悉时间复杂度,时间复杂度为On是否意味着它将比另一个建议的答案运行得更快或更慢?@Hildoby这将比我的答案运行得更快:我的答案在^2最坏情况下,而这是开启的。Hildoby,请参阅时间复杂度的解释。谢谢@CarySwoveland!这非常有效,而且确实比其他建议的解决方案快得多。但是,对于非常大的文件,我在这一行得到以下错误堆栈级别太深SystemStackError:arr.values_at*arr.size.times.to_a&keepers_idx.values.flatte,我如何解决这个问题?导致错误的文件有多大?另外,在一个问题文件中的所有元素[a,b,c]中,你知道我散列中的键的唯一数组[b,c]的数量吗?