You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby实现3x3数独生成遇阻:uniq方法多条件过滤问题

解决Ruby中筛选3元素循环排列的问题

看起来你混淆了uniq方法的用法——uniq是用来去重(根据块返回的键值合并重复项),而不是用来筛选符合条件的元素的。你写的uniq{ _1.index(1) && _1.index(2) && _1.index(3) }其实每个排列都会返回true(因为所有排列都包含1、2、3),所以uniq会认为所有元素的键都是true,最终只保留第一个排列,这显然不是你想要的结果。

你的需求分析

你想要的是3元素的循环移位排列:比如[1,2,3]、[2,3,1]、[3,1,2],这些排列是通过将基础排列循环左移/右移得到的。如果是要从所有排列中筛选出这类结果,或者直接生成它们,有两种简单的方法:


方法1:直接生成循环移位排列

如果你已经确定基础排列(比如[1,2,3]),可以用rotate方法直接生成所有循环移位结果:

base = [1, 2, 3]
cyclic_perms = 3.times.map { |i| base.rotate(i) }
# 输出:[[1, 2, 3], [2, 3, 1], [3, 1, 2]]

rotate(i)会把数组向左旋转i位,执行3次就能得到所有循环移位的排列。


方法2:从全排列中筛选符合条件的项

如果你需要从所有6种排列中筛选出循环移位的那些,可以用select方法(这才是用来过滤条件的正确方法),判断每个排列是否是基础排列的循环移位:

all_perms = (1..3).to_a.permutation.to_a
base = [1, 2, 3]
valid_perms = all_perms.select do |perm|
  # 检查当前排列是否是base的任意次数循环移位
  3.times.any? { |i| perm == base.rotate(i) }
end
# 输出:[[1, 2, 3], [2, 3, 1], [3, 1, 2]]

为什么你的uniq用法不对?

再强调一下:uniq的块是用来生成一个标识键,当两个元素的键相同时,uniq会只保留第一个。比如如果你想把循环移位的排列归为一组并只保留一个,才会用到uniq,比如:

all_perms = (1..3).to_a.permutation.to_a
# 用循环移位的基础形式作为键,实现分组去重
unique_cyclic_groups = all_perms.uniq do |perm|
  # 找到排列中最小元素的位置,将数组旋转到以最小元素开头的形式作为键
  min_idx = perm.index(perm.min)
  perm.rotate(min_idx)
end
# 输出:[[1, 2, 3], [1, 3, 2]]

这时候uniq会把循环移位的排列视为同一组,每组保留第一个元素,得到两个不同的循环组。

内容的提问来源于stack exchange,提问作者vrintle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 21:32:45