Ruby排列生成函数问题求助:输入'aabb'缺失部分排列结果及链式调用语法疑问
首先来说你的排列函数问题——你猜对了,问题确实出在.delete_if{|x,i| x[i].eql? x[i+1]}这一段,而且这部分的逻辑完全偏离了去重的需求:
1. 原代码的逻辑错误分析
str.split(//).permutation.with_index.to_a返回的是一个数组,其中每个元素是**[排列数组, 该排列在总列表中的索引]**的组合,比如对于输入'aabb',会生成类似[['a','a','b','b'], 0], [['a','b','a','b'], 1], ...这样的元素。
而你在delete_if的块里,x是排列数组,i是这个排列的全局索引。这时候x[i]是取排列数组的第i个元素(比如当i=2时,取排列的第3个元素),x[i+1]是下一个元素——这逻辑完全不是在去重,而是在删除所有“排列数组的第i个元素等于第i+1个元素”的排列(甚至当i超过排列长度时会取到nil,导致更多误删)。这直接把baab、baba、bbaa这些合法排列给过滤掉了,因为它们在全局列表中的索引位置对应的排列元素刚好有相邻相等的情况。
另外,你后面的.flatten(1).delete_if{|x| x.class == Integer}也是多余的——这是因为你用了with_index引入了整数索引,不得不删掉这些整数,但其实完全没必要加with_index。
2. 正确的去重排列实现
Ruby的permutation方法会生成所有可能的排列(包括重复的,当输入有重复字符时),所以直接用uniq就能实现去重,不需要自己写复杂的过滤逻辑。正确的代码应该是:
def permutations(str) str.chars.permutation.map(&:join).uniq end
测试这个函数:
permutations('aabb') # => ["aabb", "abab", "abba", "baab", "baba", "bbaa"]
完全符合你的预期结果。
3. 关于Ruby链式调用的语法问题
Ruby完全支持链式调用的换行写法,而且非常推荐用来提升代码可读性,只要注意以下几点:
- 方法调用的点(
.)可以放在上一行的结尾,或者下一行的开头(通常放在上一行结尾更规范)。 - 对于需要块的方法(比如
delete_if、map),可以把块和方法放在同一行,或者换行展开写块:
例如合法的链式调用写法:
# 方式1:紧凑链式 str.chars.permutation.map(&:join).uniq # 方式2:换行链式,块写在同一行 str.chars .permutation .map(&:join) .uniq # 方式3:换行链式,展开块写法 str.chars .permutation .map do |char_array| char_array.join end .uniq
你提到的str.split(//).to_a.delete_if.etc写法,注意delete_if需要跟块,不能单独写.delete_if而不提供块,否则会返回一个Enumerator对象,后续的方法调用会出错。比如正确的写法是把块和delete_if绑定在一起,而不是分开。
内容的提问来源于stack exchange,提问作者Patryk




