如果前 3 个值在 Ruby on Rail 中不唯一,则从多维数组中删除数组



好的,所以我有这个数组。较大数组中的每个数组都非常相同,十个特定值。如果我在位置3处的值是一个特定的值,那么我想迭代较大数组中其余的剩余数组,并查看位置0、1和2匹配的前3个值。如果它们匹配,我想删除原始数组。我很难过,也许有一种简单的方法?我敢肯定,我对整个编码的内容=)提前感谢您的帮助。...

这是我在的地方:

@projectsandtrials.each do |removed|
  if removed[3] == ["Not Harvested"]
    @arraysforloop = @projectsandtrials.clone
    @arraysforloop1 = @arraysforloop.clone.delete(removed)
    @arraysforloop1.each do |m|
      if (m & [removed[0], removed[1], removed[2]]).any?
        @projectsandtrials.delete(removed)
      end
    end

  end
end

让我们看看您的情况:

@projectsandtrials.each do |removed|
  // some logic, yada yada
  @projectsandtrials.delete(removed) 
end

您不能仅仅从迭代的阵列中删除内容。至少直到完成迭代为止。您应该使用的是一种过滤方法,例如reject而不是each

因此,当使用拒绝时,您应该只是返回true而不是删除那里。

我在迭代阵列时会这样考虑。

我是否希望该数组保持相同的大小并具有相同的内容?使用每个。

我是否希望该数组的大小相同,但内容不同?使用地图。

我是否希望该数组小于或等于当前大小?使用选择或拒绝。

我是否希望它最终成为一个值?使用降低。

代码

def prune(arr, val)
  arr.values_at(*(0..arr.size-4).reject { |i| arr[i][3] == val &&
    arr[i+1..i+3].transpose[0,3].map(&:uniq).all? { |a| a.size==1 } }.
      concat((arr.size-3..arr.size-1).to_a))
end

示例

arr = [ [1,2,3,4,0],
        [3,4,5,6,1],
        [3,4,5,4,2],
        [3,4,5,6,3],
        [3,4,5,6,4],
        [3,4,0,6,5],
        [2,3,5,4,6],
        [2,3,5,5,7],
        [2,3,5,7,8],
        [2,3,5,8,9],
        [2,3,5,7,0]
      ]     

请注意,arr的元素(数组)的最后值是连续的。这是为了帮助您确定已删除的prune(arr, 4)(下)的元素。

prune(arr, 4)   
   # => [[3, 4, 5, 6, 1],
   #     [3, 4, 5, 4, 2],
   #     [3, 4, 5, 6, 3],
   #     [3, 4, 5, 6, 4],
   #     [3, 4, 0, 6, 5],
   #     [2, 3, 5, 5, 7],
   #     [2, 3, 5, 7, 8],
   #     [2, 3, 5, 8, 9],
   #     [2, 3, 5, 7, 0]] 

说明

索引06的数组尚未包含在返回的数组中。

arr[0][1,2,3,4,0])尚未包括在内,因为arr[0][3] = val = 4arr[1]arr[2]arr[3]全部开始[3,4,5]

arr[6][2,3,5,4,6])尚未包括在内,因为arr[6][3] = 4arr[7]arr[8]arr[9]都开始[2,3,5]

arr[2][3,4,5,5,2])被包括在内,因为arr[2][3] = 4arr[3][0,3]arr[4][0,3]arr[5][0,3]并非全部相等(即arr[5][2] = 0)。

请注意,arr的最后三个要素将始终包含在返回的数组中。

现在让我们检查计算。首先考虑以下。

arr.size
  #=> 11
a = (0..arr.size-4).reject { |i| arr[i][3] == val &&
  arr[i+1..i+3].transpose[0,3].map(&:uniq).all? { |a| a.size==1 } }
  #=> (0..7).reject { |i| arr[i][3] == val &&
    arr[i+1..i+3].transpose[0,3].map(&:uniq).all? { |a| a.size==1 } }
  #=> [1, 2, 3, 4, 5, 7]

考虑i=0reject的块计算(Ressect val=4)。

arr[i][3] == val && arr[i+1..i+3].transpose[0,3].map(&:uniq).all? {|a| a.size==1 }}
  #=> 4 == 4 && arr[1..3].transpose[0,3].map(&:uniq).all? { |a| a.size==1 }
  #=> [[3,4,5,6,1],
  #    [3,4,5,4,2],
  #    [3,4,5,6,3]].transpose[0,3].map(&:uniq).all? { |a| a.size==1 }
  #=> [[3, 3, 3],
  #    [4, 4, 4],
  #    [5, 5, 5],
  #    [6, 4, 6],
  #   [1, 2, 3]][0,3].map(&:uniq).all? { |a| a.size==1 }
  #=> [[3, 3, 3],
  #    [4, 4, 4],
  #    [5, 5, 5]].map(&:uniq).all? { |a| a.size==1 }
  #=> [[3], [4], [5]].all? { |a| a.size==1 }
  #=> true

意味着arr[0]将被拒绝;即,未包含在返回的数组中。其余的块计算(对于i=1,...,10)是相似的。

我们已经计算出

a #=> [1, 2, 3, 4, 5, 7]

arr所有元素的索引,除了要保留的最后一个3。在a中,我们添加了arr的最后三个元素的索引。

b = a.concat((arr.size-3..arr.size-1).to_a)
  #=> a.concat((8..10).to_a)
  #=> a.concat([8,9,10])
  #=> [1, 2, 3, 4, 5, 7, 8, 9, 10] 

最后,

arr.values_at(*b)

返回示例中给出的数组。

您的代码段似乎还不错,尽管有几件事要注意:

  1. @arraysforloop.clone.delete(removed)删除了removed数组的所有出现(不仅是第一个)。例如。[1,2,3,1] .DELETE(1)会给您[2,3]。您可以使用@projectsandtrials和DELETE_AT方法的迭代器来修复它。

  2. delete方法返回您传递给它的同一参数(或者如果找不到匹配的话,则无需返回)。因此,@arraysforloop1 = @arraysforloop.clone.delete(removed)使您的@arraysforloop1仅包含删除的数组的元素!删除作业可以为您节省。

  3. 我没有理由拥有两个克隆的阵列@arraysforloop@arraysforloop1,因为以后不使用前一个。可能是我们可以省略其中之一吗?

  4. @projectsandtrials.delete(removed)只要您现在迭代相同的数组,就会使您处于一个奇怪的状态。这可能会导致您在删除一个元素后错过了正确的下一个元素。这是一个简单的片段来说明行为:

    > a = [1,2,3]
    > a.each{|e, index| puts("element is: #{e}"); a.delete(1);}
    element is: 1
    element is: 3
    

    如您所见,删除元素1后,循环直接移至element 3,省略了2(因为它成为数组中的第一个元素,并且算法认为它已经已经处理过)。

使它不那么混乱的可能性之一就是将其拆分为一束方法。这是一个选项:

def has_searched_element? row
  # I leave this method implementation to you
end
def next_rows_contain_three_duplicates?(elements, index)
  # I leave this method implementation to you
end
def find_row_ids_to_remove elements
  [].tap do |result|
    elements.each_with_index do |row, index|
      condition = has_searched_element?(row) && next_rows_contain_three_duplicates?(elements, index)
      result << index if condition
    end
  end
end
row_ids_to_remove = find_row_ids_to_remove(@projectsandtrials)
# now remove all the elements at those ids out of @projectsandtrials

最新更新