【问题标题】:How do I split an array into smaller arrays bsaed on a condition?如何根据条件将数组拆分为更小的数组?
【发布时间】:2017-12-11 23:12:40
【问题描述】:

红宝石 2.4。我有一个字符串数组

2.4.0 :007 > arr = ["a", "b", "g", "e", "f", "i"]
 => ["a", "b", "g", "e", "f", "h", "i"]

如何根据条件将我的数组拆分为更小的数组?我有一个函数——“contains_vowel”,如果字符串包含“a”、“e”、“i”、“o”或“u”,则返回 true。如何使用“contains_vowel”的分隔函数将字符串数组拆分为更小的数组?也就是说,对于上述情况,较小数组的结果数组将是

[["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]

如果较大数组中的一个元素满足条件,它将成为一个元素的数组。

【问题讨论】:

    标签: arrays ruby split


    【解决方案1】:
    arr = ["a", "b", "g", "e", "f", "i"]
    
    r = /[aeiou]/
    arr.slice_when { |a,b| a.match?(r) ^ b.match?(r) }.to_a
       => [["a"], ["b", "g"], ["e"], ["f"], ["i"]]
    

    String#match? 在 Ruby v2.4 中首次亮相。对于早期版本,您可以使用(例如)!!(b =~ r),其中!! 将真/假值转换为true/false。这种转换是必要的,因为 XOR 运算符 ^ 具有双重职责:当 a^b 中的 abtruefalsenil 时,它是一个逻辑 XOR,并且是按位的操作数为整数时异或,如2^6 #=> 4(2.to_s(2) #=> "10"; 6.to_s(2) #=> "110"; 4.to_s(2) #=> "100")。

    【讨论】:

    • 或者使用OP的函数:arr.slice_when{|a,b| contains_vowel(a) ^ contains_vowel(b)}.to_a
    • @Mark,...或一个过程,但我这样做只是为了多样化。
    • 这个。 XORmatch 是要走的路。
    • 可能会注意到这是针对>= 2.4 并且在技术上不符合此条件“如果较大数组的元素满足条件,它将成为一个元素的数组。”虽然我不确定这实际上是意图
    【解决方案2】:

    另一种给猫剥皮的方法

    def contains_vowel(v) 
       v.count("aeiou") > 0
    end 
    def split_by_substring_with_vowels(arr)
      arr.chunk_while do |before,after|
        !contains_vowel(before) & !contains_vowel(after)
      end.to_a
    end
    split_by_substring_with_vowels(arr)
    #=> [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
    

    它的作用:

    • 传递每个连续的 2 个元素
    • 当其中任何一个包含元音时拆分

    以你的其他Array为例

    arr = ["1)", "dwr", "lyn,", "18,", "bbe"]
    split_by_substring_with_vowels(arr)
    #=> [["1)", "dwr", "lyn,", "18,"], ["bbe"]]
    

    进一步的例子:(如果您希望包含连续元素的元音留在同一组中)

    def split_by_substring_with_vowels(arr)
      arr.chunk_while do |before,after|
        v_before,v_after = contains_vowel(before),contains_vowel(after)
        (!v_before & !v_after) ^ (v_before & v_after)
      end.to_a
    end
    
    arr = ["1)", "dwr", "lyn,", "18,", "bbe", "re", "rr", "aa", "ee"]
    split_by_substring_with_vowels(arr)
    #=> [["1)", "dwr", "lyn,", "18,"], ["bbe", "re"], ["rr"], ["aa", "ee"]]
    

    这会检查之前和之后是否都不是元音如果它们都是元音

    【讨论】:

      【解决方案3】:

      我可能会使用chunk,它会在每次其块的值更改时拆分数组。 Chunk 返回[block_value, [elements]] 对的列表,我使用.map(&:last) 仅获取元素的子列表。

      arr = ["a", "b", "g", "e", "f", "h", "i"]
      
      def vowel?(x); %w(a e i o u).include?(x); end
      
      arr.chunk{|x| vowel?(x)}.map(&:last)
      
      => [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
      

      【讨论】:

      • 不确定我是否剪切和粘贴了错误,但如果我的数组是 ["1)"、"dwr"、"lyn,"、"18,"、"bbe"],则应用您的逻辑产生 [["1)", "dwr", "lyn,", "18,", "bbe"]],但它应该是两个数组 -- [["1)", "dwr", "lyn ,", "18,"], ["bbe"]] 因为我的数组中只有一个元素包含元音(应该在那里拆分产生两个数组)
      • 我的 vowel? 函数不适用于这些示例。如果你使用你之前写的那一个呢?
      【解决方案4】:
      contains_vowel = ->(str) { !(str.split('') & %w|a e i o u|).empty? }
      
      _, result = ["a", "b", "g", "e", "f", "h", "i"].
                       each_with_object([false, []]) do |e, acc|
         cv, acc[0] = acc[0], contains_vowel.(e)
         cv ^ acc.first ? acc.last << [e] : (acc.last[-1] ||= []) << e
      end
      result
      #⇒ [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
      

      我们在这里做什么:

      1. contains_vowel 是一个 lambda,用于检查字符串是否包含元音。
      2. 我们减少输入数组,收集最后一个值(是否包含先前处理的元音字符串)和result
      3. cv ^ acc.first 在最后一步检查它是否是元音触发器。
        1. 不管是,我们在结果中追加一个新数组
        2. 无论是不是,我们将字符串附加到结果中的最后一个数组。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-09-16
        • 1970-01-01
        • 2016-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-07
        • 1970-01-01
        相关资源
        最近更新 更多