【问题标题】:Pick elements on (un)even index from an array in Groovy从 Groovy 中的数组中选择(非)偶数索引上的元素
【发布时间】:2019-11-07 18:54:22
【问题描述】:

我有一个包含数字的 Groovy 数组。我需要创建两个仅包含偶数位数的新数组。该数组中的位置不均匀。

我能找到的最好的方法是这样,但我觉得这里还有很大的改进空间:

def evenDigits = digits
    .indexed(1)
    .findAll { i, v -> i % 2 == 0 }
    .collect { it.value }

显然unevenDigits 变体将简单地检查findAll 闭包中的模数与1 而不是0。

有谁知道这段代码是否可以改进或压缩?

【问题讨论】:

  • 为了打高尔夫球:.collect{ it.value } 只是.values()。
  • @cfrick 天哪,谢谢!

标签: groovy


【解决方案1】:

一种“不那么聪明”(当然也更高效)的解决方案:

def evens = [], odds = []
digits.eachWithIndex{ v, ix -> ( ix & 1 ? odds : evens ) << v }

【讨论】:

    【解决方案2】:

    您可以使用groupBy 将结果分为奇数/偶数项。例如

    groovy:000> ["a","b","c"].indexed(1).groupBy{ i, _ -> i & 1 }.collectEntries{ k, v -> [k as Boolean, v.values()] }
    ===> [true:[a, c], false:[b]]
    

    【讨论】:

    • 不一定必须在一个语句中。这个解决方案看起来更聪明,但也更难弄清楚发生了什么。
    • 我喜欢a &amp; 1 而不是a % 2 检查
    • @injecteer 确实可能更快,但性能不会成为问题(12 位数,一天执行几次)。
    • @Koen 确实如此。我正在为 10k rps 的用例寻找更大的图景
    【解决方案3】:

    另一个使用withIndex() 和findResults() 组合的“Groovy”解决方案。

    • withIndex() 将 List&lt;T&gt; 转换为 List&lt;Tuple2&lt;T,Integer&gt;&gt; - 值索引元组列表。
    • findResults(closure) 运行过滤转换 - 它接收到的闭包是一个转换谓词。在我们的例子中,它检查索引值是奇数还是偶数,如果谓词匹配,则从元组中提取值。 (过滤掉所有 null 值。)

    简洁明了。需要最少数量的转换:List&lt;T&gt; 到 List&lt;Tuple2&lt;T,Integer&gt;&gt;,然后进行一次迭代以产生最终结果。

    def numbers = [1,2,3,4,5,6,2,3,1] // Some test data
    
    def even = { t -> t.second % 2 == 0 ? t.first : null } // "Even" transforming predicate
    def odd = { t -> t.second % 2 == 1 ? t.first : null } // "Odd" transforming predicate
    
    def evens = numbers.withIndex(1).findResults even
    def odds = numbers.withIndex(1).findResults odd
    
    // And some assertions to test the implementation
    assert evens == [2,4,6,3]
    assert odds == [1,3,5,2,1]
    

    【讨论】:

    • 我想我更喜欢findAll 使用布尔返回闭包而不是findResults 返回值或null。我也更喜欢indexed 而不是withIndex,但我猜这都是个人喜好。
    【解决方案4】:

    另一种选择,对于单次传递(但由于indexed 仍具有中间集合),将是减少:

    def (odd,even) = digits.indexed().inject([[],[]]){ acc, it -> acc[it.key&1] << it.value; acc }
    

    【讨论】:

    • 我非常感谢您的努力,您应该得到支持,但我不能将此传递给其他开发人员来维护它。
    • 你把它放在一个函数中,给它一个合适的名字,记录一些测试中的行为,你就完成了。使用reduce,它基本上类似于groupBy,但之后不再对数据进行整形。
    【解决方案5】:

    我想出了这个,但这可能不是最聪明的方法。

        def isEven = { int x -> x % 2 == 0 ? x : null}
    
        def (digits, evens, odds) = [[1, 2, 3, 4, 5, 6, 7, 8, 9], [], []] 
    
        digits.each { 
            if (isEven(it))
                evens.add(isEven(it))
        }
    
        odds = digits - evens 
    
        assert evens == [2, 4, 6, 8]
        assert odds == [1, 3, 5, 7, 9]
    

    【讨论】:

    • 我的错误,我不是指偶数或奇数位,而是偶数和奇数位置的数字。问题已更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-09
    • 1970-01-01
    • 2020-09-28
    • 2019-01-11
    • 1970-01-01
    • 1970-01-01
    • 2020-02-08
    相关资源
    最近更新 更多