【问题标题】:How do I merge consecutive elements in an array subject to a constraint?如何合并受约束的数组中的连续元素?
【发布时间】:2017-07-02 16:52:15
【问题描述】:

我使用的是 Ruby 2.4。我有一个字符串数组,如果它们之间有一个“-”,我想加入连续的元素。所以,例如,如果我有

["a", "-", "b", "c"]

我希望结果是

["a - b", "c"]

如果数组是类似的

["a-", "b", "c"]

我希望结果是

["a- b", "c"]

或者如果数组是

["a", "-b", "c", "d"]

我希望结果是

["a -b", "c", "d"]

一个例外是,如果相邻的标记之一已经包含“-”,我不想将它们合并在一起。例如,如果我有

["a", "-", "b-c", "d"]

我希望数组保持为

["a", "-", "b-c", "d"]

Cary 帮我想出了这个功能

  def join_some(arr, special_chars_arr)
    arr.drop(1).each_with_object([arr.first]).with_index(1) do |(s,a),i|
      puts "s: #{s} a: #{a.last}"
      if ((special_chars_arr.include?(s[0]) && (i < arr.size - 1 || s.size > 1)) ||
          (special_chars_arr.include?(a.last[-1]) && (i > 1 || a.last.size > 1))) &&
         a.last !~ Regexp.union(special_chars_arr)
        a.last << " #{s}"
      else
        a << s
      end
    end
  end

但问题是如果我的数组是

["a", "-", "b-c"]

调用 join_some(arr, ["-"]) 把事情变成

["a - b-c"]

我不想合并相邻的标记,因为其中一个标记已经包含破折号。我怎样才能修改我的方法来做我想做的事?

【问题讨论】:

  • 你能有["a", "-", "b", "-", "c"]吗?如果是这样,期望的结果是什么? ["a-", "-b"]呢?
  • 第二种情况应该保持为 ["a-", "-b"] 因为第二个标记已经包含一个 "-"。对于第一种情况,如果可能的话,我想要 ["a - b - c"]。如果只有 ["a", "-", "b", "-", "c"] 和所有其他情况都有效,那很好。
  • 以这种方式处理第一种情况实际上更容易。 ["-", "a", "b"]["a", "b", "-"] 呢? ["- a", "b"]["a", "b -"] 或其他什么都不会改变吗?换句话说,对于成对连接,"-" 的处理方式与 "a-""-a" 的处理方式有何不同?
  • 对于 ["a", "b", "-"],它应该保持为 ["a", "b", "-"],因为 "- 之后没有标记“ 元素。与 ["- a", "b"] 相同 -- 它应该保持为 ["- a", "b"],因为 "-" 之前没有元素。希望这是有道理的。

标签: arrays ruby string


【解决方案1】:

基于终端元素追加到新数组

可能有更紧凑的方式来表达这一点,但如果您正在处理字符串值,那么您可以简单地遍历每个元素来决定是否应该将它附加到新数组的最后一个元素,或者添加为单独的元素。例如:

old_array = ["a", "-", "b", "c", "d", "-", "e", "-", "f"]
new_array = []

old_array.each do |value|
  if new_array.last.to_s.end_with? '-' or value.eql? '-'
    new_array.last << value
  else
    new_array.push value
  end
end;

new_array
#=> ["a-b", "c", "d-e-f"]

请注意,即使您在序列中有多个破折号或减号,这也是相当稳健的,如果您没有固定的序列长度,这一点很重要。

【讨论】:

  • 谢谢,但这不适用于我提到的最后一种情况——[“a”、“-”、“b-c”]。如果其中一个已经包含我的特殊字符,我不想合并连续的元素。您的函数 yeidls "["a-b-c"]" 用于上述内容,但数组应保持为 ["a", "-", "b-c"],因为最后一个字符串包含特殊字符。
【解决方案2】:
def massage(arr)
  arr.drop(1).each_with_object([arr.first]) do |s,a|
    a <<
    case
    when s == '-'
      s
    when a.last == '-'
      ((a.size > 1) && (a[-2] =~ / - [^ -]+\z|\A[^-]+\z/) && (s !~ /-/)) ?
        [*a.pop(2),s].join(' ') : s
    when a.last.end_with?('-') ^ s.start_with?('-')
      a.pop << ' ' << s
    else
      s
    end
  end
end    

examples = [["a","-","b","c"], ["a-","b","c"], ["a","-b","c","d"],
            ["a","-","b-c","d"], ["-", "a", "b"], ["a", "b", "-"],
            ["a", "-", "b", "-", "c"], ["a", "-", "b", "-", "c", "-d"]]

examples.each { |a| puts "#{a.to_s.ljust(32)}  \#=> #{massage(a)}" }
["a", "-", "b", "c"]              #=> ["a - b", "c"]
["a-", "b", "c"]                  #=> ["a- b", "c"]
["a", "-b", "c", "d"]             #=> ["a -b", "c", "d"]
["a", "-", "b-c", "d"]            #=> ["a", "-", "b-c", "d"]
["-", "a", "b"]                   #=> ["-", "a", "b"]
["a", "b", "-"]                   #=> ["a", "b", "-"]
["a", "-", "b", "-", "c"]         #=> ["a - b - c"]
["a", "-", "b", "-", "c", "-d"]   #=> ["a - b - c -d"]

^ 是逻辑和按位 XOR 运算符。这里两个操作数分别是truefalse(逻辑),所以如果一个操作数是true 而另一个是false,则返回true

【讨论】:

  • 谢谢。只有一件事——如果其中一个标记已经有一个“-”,我不想将它们融合在一起。所以在你的例子中,你有 ["a", "-", "b-c", "d"],但是 sicne "b-c" 已经包含一个 "-",我希望结果数组保持 ["a" , "-", "b-c", "d"].
  • 感谢您的澄清。我修好了。
  • 我做了一些小的修改。请告诉我结果是否都是你想要的。
  • 我做了一些小的修改。请告诉我结果是否都是您想要的(尤其是最后一个示例)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多