在Ruby中,你能随机化[1a,1b,1c,1d,2a,2b,2c,2d,3a,3b,3c,3d,4a,4b,4c,4d],使连续的整数不同吗?

gg0vcinb  于 2023-03-22  发布在  Ruby
关注(0)|答案(3)|浏览(140)

我参与了一项研究,受试者从4个类别(1,2,3,4)输入,每个类别有4个单词(a,b,c,d)。每个受试者的单词顺序需要随机化,但连续的单词应该来自不同的类别。
我是一个相当新的编码,并一直在努力的算法,可以做到这一点,但它是越来越长和复杂,我觉得应该有一个更简单的方法来做,是不容易出错。任何帮助将不胜感激!

nhjlsmyf

nhjlsmyf1#

下面是我在评论中建议的“蛮力”方法的实现。

source = ["1a","1b","1c","1d","2a","2b","2c","2d","3a","3b","3c","3d","4a","4b","4c","4d"]
valid = []
num_valid = 100

until valid.length >= num_valid do
  candidate = source.shuffle

  if candidate.each_cons(2).all? {|a,b| a[0] != b[0] }
    valid |= [candidate]
  end
end

运行此命令后,valid将包含100个不同的有效列表。

qq24tv8q

qq24tv8q2#

分解问题(以一种方式;还有其他的):

  • 需要非重复类别的列表
  • TBD:[a, b, a, ...]怎么样
  • 例如,每组单词.长度组合是否需要每个类别中的一个单词
  • TBD:猫每组单词的顺序都需要一样吗
  • 例如:
  • [c, b, d, a, c, b, d, a, ...](每个单词组相同的猫)或
  • [c, b, d, a, b, a, c, d, ...](不同的猫)
  • 无论哪种方式都有微小的调整
  • 该列表的长度为cats.length * words.length(组合数)

详细但清楚地说:这是一个类别shuffle的平面图,每个words.length一个,如果需要,可以重新shuffle (如果需要),直到shuffle的第一个条目不同于前一个shuffle的最后一个条目。
将其分成words.length块,并将每个类别与混洗单词列表中的单词相关联。
很可能是一个简单的实现,但相当清晰,还有十几行或两行代码,没有试图变得聪明(我绝对没有:rofl:)。换句话说:它不需要非常复杂就能满足需求--也许值得尝试以不同的方式来考虑它。

tquggr8v

tquggr8v3#

这里有一个方法,它与@user513951的方法略有不同,但可能在数组较大时更有效。与前面的方法一样,它会循环,直到随机选择具有所需的属性。这两种方法都会产生统计随机样本(在软件中产生真正的随机值时受到限制)。
前面的方法提取块{ |a,b| a[0] != b[0] }中两个字符串的类别。有不超过9个类别。如果类别可能由两个或更多的数字组成,数字将不得不从字符串的前面剥离。可能有一个前-处理步骤,使ab在前面提到的块两个元素数组中(这将需要在最后进行一些整理)。这将是对早期方法的简单更改。
如果我们被赋予

a = ["1a", "1b", "1c", "1d", "20a", "20b", "20c", "20d",
     "3a", "3b", "3c", "3d", "41a", "41b", "41c", "41d"]

我们可以从计算1开始

arr = a.map { |s| s.split(/(?<=\d)(?=\D)/) }
  #=> [["1", "a"], ["1", "b"], ["1", "c"], ["1", "d"],
  #    ["20", "a"], ["20", "b"], ["20", "c"], ["20", "d"],
  #    ["3", "a"], ["3", "b"], ["3", "c"], ["3", "d"],
  #    ["41", "a"], ["41", "b"], ["41", "c"], ["41", "d"]]

与前面的方法相比,我建议的唯一变化是首先获得满足所需属性的类别随机序列,一旦找到,我将把它转换为一个返回值,该返回值仍然是一个无偏样本选择。
实际上,我将块{ |a,b| a[0] != b[0] }简化为{ |x,y| x != y },其中xy是类别。
首先创建一个哈希,将类别Map到它们的单词数组。

h = arr.each_with_object(Hash.new { |h,k| h[k] = [] }) do |(cat,word),h|
  h[cat] << word
end
  #=> {"1"=>["a", "b", "c", "d"], "20"=>["a", "b", "c", "d"],
  #    "3"=>["a", "b", "c", "d"], "41"=>["a", "b", "c", "d"]}

接下来,打乱每个值的元素以在以后保持随机性。

h.transform_values!(&:shuffle)
  #=> {"1"=>["b", "d", "a", "c"], "20"=>["b", "c", "a", "d"],
  #    "3"=>["d", "b", "c", "a"], "41"=>["a", "d", "c", "b"]}

然后选择按其值的大小复制的键(对于所有键,不需要完全相同)。

keys = h.each_with_object([]) { |(k,v),a| a.concat([k]*v.size) }
  #=> ["1", "1", "1", "1", "20", "20", "20", "20",
  #    "3", "3", "3", "3", "41", "41", "41", "41"]

现在找到一个满足所需属性的类别序列。

loop do
  n += 1
  keys.shuffle!
  break keys if keys.each_cons(2).all? { |x,y| x != y }
end
  #=> ["1", "41", "3", "20", "41", "20", "1", "20",
       "3", "41", "1", "3", "1", "20", "41", "3"]

(Upon多次执行此操作,总是需要70次迭代才能找到有效序列。
最后,为每个类别添加随机化的单词,以生成一个满足所需属性的随机数组。

keys.map { |k| "#{k}#{h[k].shift}" }
  #=> ["1b", "41a", "3d", "20b", "41d", "20c", "1d", "20a",
  #    "3b", "41c", "1a", "3c", "1c", "20d", "41b", "3a"]
  1. (?<=\d)是一个 * 正向后查找 *,它Assert匹配的前面是一个数字。(?=\D)是一个 * 正向前查找 *,它Assert匹配的后面是一个字符而不是一个数字。因此,这个正则表达式匹配字符串中最后一个数字和第一个非数字之间的零宽度位置。

相关问题