当前位置: 首页 > 知识库问答 >
问题:

获取Ruby数组中最长的前缀

华锦
2023-03-14

我有一个数组。在每个子数组中,如果两个或多个元素共享一个长度等于或大于8的前缀,那么我想用它们最长的前缀替换这些元素。对于此阵列:

m = [
  ["A", "97455589955", "97455589920", "97455589921"],
  ["B", "2348045101518", "2348090001559"]
]

我希望输出如下:

n = [
  ["A", "974555899"],
  ["B", "2348045101518", "2348090001559"]
]

对于m中的第一个子数组,最长前缀为长度为9的974555899。

974555899-55
974555899-20
974555899-21

对于第二个子阵列,最长的前缀是长度为5的23480,长度小于8。在这种情况下,第二个子阵列保持原样。

23480-45101518
23480-90001559

对于此输入:

m = [
  ["A", "2491250873330", "249111222333", "2491250872214", "2491250872213"],
  ["B", "221709900000"],
  ["C", "6590247968", "6590247969", "6598540040", "65985400217"]
]

输出应如下所示:

[
  ["A", "2491250873330", "249111222333", "249125087221"],
  ["B", "221709900000"],
  ["C", "659024796", "65985400"]
]

对于数组m[0][code>,其四个数字之间没有足够长的前缀,但在m[0][2][code>和m[0][3][code>之间有一个长度为12的前缀。对于数组m[2][code>,在m[2][0][code>和m[2][1][code>之间有长度为9的前缀“659024796”,在m[2][2][code>和m[2][3][code>之间有长度为8的前缀“65985400”。

我构建了以下代码:

m.map{|x, *y|
  [x, y.map{|z| z[0..7]}.uniq].flatten
}

通过我的代码和第一个输入,我得到了这个输出。

[
  ["A", "97455589"],
  ["B", "23480451", "23480900"]
]

我一直在研究如何在不设置固定长度的情况下动态获取公共前缀。

共有3个答案

叶恩
2023-03-14

您的任务可以分为两部分:计算最大公共数和修改原始数组。

最大公共数在数组上运行,因此,它应该是数组的一种方法。

计算LCN后,您可以将其长度与限制(即8)进行比较。

class Array
  def lcn
    first.length.times do |index|
      numb = first[0..index]
      return numb unless self[1..-1].all? { |n| n.start_with?(numb) }
    end

    first
  end
end

def task(m, limit = 8)
  m.map { |i,*n| [i, n.lcn.length >= limit ? n.lcn : n].flatten }
end

task(m) # => [["A", "9745558995"], ["B", "2348045101518", "2348090001559"]]

在您的解决方案中,实际上并没有实现lcn查找和过滤输出。

阎建德
2023-03-14

这是一个有趣的问题。以下是我的解决方案:

def lcn(lim, *arr)
  # compute all substrings of lengths >= lim and build a lookup by length
  lookup = lcn_explode(lim, arr)

  # first pass: look for largest common number among all elements
  res, = lcn_filter(arr, lookup) { |size| size == arr.size }

  return res unless res.empty?

  # second pass: look for largest common number among some elements
  res, rem = lcn_filter(arr, lookup) { |size| size > 1 }

  # append remaining candidates with no matches
  res.concat(rem)
end

def lcn_explode(lim, arr)
  memo = Hash.new { |h, k| h[k] = Array.new }

  arr.uniq.each do |n|
    lim.upto([n.size, lim].max) do |i|
      memo[i] << [n[0, i], n]
    end
  end

  memo
end

def lcn_filter(arr, lookup)
  memo = []

  lookup.keys.sort!.reverse_each do |i|
    break if arr.empty?

    matches = Hash.new { |h, k| h[k] = Array.new }
    lookup[i].each do |m, n|
      matches[m] << n if arr.include?(n)
    end

    matches.each_pair do |m, v|
      next unless yield v.size

      memo << m

      # remove elements from input array so they won't be reused
      arr -= v
    end
  end

  return memo, arr
end

你这样使用它:

p lcn(8, "97455589955", "97455589920", "97455589921") => ["974555899"]

或:

m.each do |key, *arr|
  p [key, *lcn(8, *arr)]
end

哪些打印:

["A", "249125087221", "2491250873330", "249111222333"]
["B", "221709900000"]
["C", "659024796", "65985400"]
白永昌
2023-03-14

密码

def doit(arr, min_common_length)
  arr.map do |label, *values|
    [label, values.group_by { |s| s[0, min_common_length] }.
      map { |_,a| a.first[0, nbr_common_digits(a, min_common_length)] }]
  end
end

def nbr_common_digits(a, min_common_length)
  max_digits = a.map(&:size).min
  return max_digits if max_digits == min_common_length + 1
  (min_common_length..max_digits).find { |i|
    a.map { |s| s[i] }.uniq.size > 1 } || max_digits
end

示例

arr = [["A","2491250873330","249111222333","2491250872214","2491250872213"],
       ["B","221709900000"],
       ["C","6590247968","6590247969","6598540040","65985400217"]]

doit(arr, 8)
  #=> [["A", ["249125087", "249111222333"]],
  #    ["B", ["221709900000"]],
  #    ["C", ["659024796", "65985400"]]]

解释说明

让我们首先考虑helper方法,nbr_common_digits。假设

a = ["123467", "12345", "1234789"]
min_common_length = 2

然后,步骤如下。

max_digits = a.map(&:size).min
  #=> 5 (the length of "12345")
max_digits == min_common_length + 1
  #=> 5 == 2 + 1
  #=> false, so do not return max_digits
b = (min_common_length..max_digits).find { |i| a.map { |s| s[i] }.uniq.size > 1 }
  #=> (2..5).find { |i| a.map { |s| s[i] }.uniq.size > 1 }
  #=> 4

此时,我们必须考虑当所有字符串的前5个字符相等时,b将等于nil的可能性。在这种情况下,我们应该返回最大\u位数,这就是为什么我们需要以下内容。

b || max_digits
  #=> 4

在doit中,步骤如下所示。

min_common_length = 8

首先,我们使用可枚举的#group\u by按值的第一个min\u common\u长度数字对值进行分组。

arr.map { |label, *values| [label,
  values.group_by { |s| s[0, min_common_length] }] }
  #=> [["A", {"24912508"=>["2491250873330", "2491250872214", "2491250872213"],
  #           "24911122"=>["249111222333"]}],
  #    ["B", {"22170990"=>["221709900000"]}],
  #    ["C", {"65902479"=>["6590247968", "6590247969"],
  #           "65985400"=>["6598540040", "65985400217"]}]]

第二步是计算最长公共长度,并根据需要替换值。

arr.map do |label, *values| [label,
  values.group_by { |s| s[0, min_common_length] }.
         map { |_,a| a.first[0, nbr_common_digits(a, min_common_length)] }]
end
  #=> [["A", ["249125087", "249111222333"]],
  #    ["B", ["221709900000"]],
  #    ["C", ["659024796", "65985400"]]]

第二个映射块中的第一个块变量(其值等于具有nbr\U common\U长度的字符串--“按分组条件分组”)由下划线(合法的局部变量)表示,表示未在块计算中使用该变量。

 类似资料:
  • 本文向大家介绍如何获取PHP数组中最长字符串的长度,包括了如何获取PHP数组中最长字符串的长度的使用技巧和注意事项,需要的朋友参考一下 array_map函数可用于获取长度,而max函数可用于获取最长字符串的长度。 以下是相同的代码示例- 示例 输出结果 这将产生以下输出-

  • 问题内容: 我需要获取行和列的2D数组的长度。我已经使用以下代码成功完成了此操作: 这将按预期打印出5、10。 现在看一下这一行: 注意,实际上我必须引用特定的行才能获取列的长度。对我来说,这似乎非常丑陋。此外,如果数组定义为: 然后,当尝试获取长度时,代码将失败。有其他方法(更智能)吗? 问题答案: 考虑 每行的列长不同。如果要通过固定大小的2D数组支持某些数据,请在包装器类中为固定值提供吸气剂

  • 在二维数组中获取最大,即行数和,即列数的最佳和有效方法是什么? 希望在每种情况下,时间复杂度都低于。这里没有循环,仍然可以找到最大。 例如,如果我有一个这样的数组 然后我想在这里得到和作为结果。 有人能帮我吗?

  • 问题内容: 如果不知道该如何获取数组的第二维?仅给出第一维度。 例如,在 如何获得的第二维的值,即3。 谢谢 问题答案: 哪 三个? 您已经创建了一个多维数组。是一个int数组的数组;您有两个长度为三的数组。 会给你第一个数组的长度。 另外值得注意的是,您不必像以前那样初始化多维数组,这意味着所有数组的长度不必相同(或根本不存在)。

  • 本文向大家介绍JS获取数组最大值、最小值及长度的方法,包括了JS获取数组最大值、最小值及长度的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了JS获取数组最大值、最小值及长度的方法。分享给大家供大家参考,具体如下: 希望本文所述对大家JavaScript程序设计有所帮助。

  • 我有一个背景工作,需要合并很多项目在一起。我想将其拆分为多个“子作业”,每个子作业合并数据的一个子集,然后最后一个过程将所有“子作业”的输出合并在一起。 一种简单的方法是将数据分成x元素组。问题是最后一个组可能有1个元素的剩余部分,因此它将是一个“noop”。我想找到最佳的“x”,这样组就大致相等,并且每个组中有最小和最大数量的元素(例如,不少于10个元素,不超过20个) 在Ruby中有什么好的算