在Ruby数组中生成一组随机对时,我想阻止生成具有相同项的对。
例如:
[1,1,2,2,3,4].shuffle.each_slice(2).to_a
可能会产生:
[[1, 1], [3, 4], [2, 2]]
我希望能够确保它产生如下结果:
[[4, 1], [1, 2], [3, 2]]
提前感谢您的帮助!
答案 0 :(得分:2)
arr = [1,1,2,2,3,4]
loop do
sliced = arr.shuffle.each_slice(2).to_a
break sliced if sliced.none? { |a| a.reduce(:==) }
end
答案 1 :(得分:1)
以下是产生所需结果的三种方法(不包括重复采样的方法,直到找到有效的样本)。以下数组将用于说明。
arr = [1,4,1,2,3,2,1]
使用Array#combination和Array#sample
如果允许采样对具有两次相同的数字,则样本空间将为
arr.combination(2).to_a
#=> [[1, 4], [1, 1], [1, 2], [1, 3], [1, 2], [1, 1], [4, 1], [4, 2],
# [4, 3], [4, 2], [4, 1], [1, 2], [1, 3], [1, 2], [1, 1], [2, 3],
# [2, 2], [2, 1], [3, 2], [3, 1], [2, 1]]
包含相同值两次的对 - 此处为[1, 1]
和[2, 2]
- 不需要,因此可以从上面的数组中删除它们。
sample_space = arr.combination(2).reject { |x,y| x==y }
#=> [[1, 4], [1, 2], [1, 3], [1, 2], [4, 1], [4, 2], [4, 3],
# [4, 2], [4, 1], [1, 2], [1, 3], [1, 2], [2, 3], [2, 1],
# [3, 2], [3, 1], [2, 1]]
我们显然要从arr.size/2
中抽取sample_space
元素。根据是否要完成with or without replacement,我们会写
sample_space.sample(arr.size/2)
#=> [[4, 3], [1, 2], [1, 3]]
没有替换的采样和
Array.new(arr.size/2) { sample_space.sample }
#=> [[1, 3], [4, 1], [2, 1]]
用于替换的采样。
每对的样本元素依次为方法1
此方法与下一个方法一样,只能用于替换样本。
让我们首先考虑对一对进行抽样。我们可以通过从arr
中随机选择对中的第一个元素来执行此操作,删除arr
中该元素的所有实例,然后从arr
的左侧对第二个元素进行采样。
def sample_one_pair(arr)
first = arr.sample
[first, second = (arr-[first]).sample]
end
要绘制arr.size/2
对的样本,我们执行以下操作。
Array.new(arr.size/2) { sample_one_pair(arr) }
#=> [[1, 2], [4, 3], [1, 2]]
每对的样本元素依次为方法2
这种方法是一种非常快速的方法,可以替换大量的对。与之前的方法一样,它不能用于无需替换的样本。
首先,计算 cdf (累积分布函数)以随机绘制arr
元素。
counts = arr.group_by(&:itself).transform_values { |v| v.size }
#=> {1=>3, 4=>1, 2=>2, 3=>1}
def cdf(sz, counts)
frac = 1.0/sz
counts.each_with_object([]) { |(k,v),a|
a << [k, frac * v + (a.empty? ? 0 : a.last.last)] }
end
cdf_first = cdf(arr.size, counts)
#=> [[1, 0.429], [4, 0.571], [2, 0.857], [3, 1.0]]
这意味着有一个概率为0.429(四舍五入)随机抽取1
,0.571抽取1
或4
,0.857抽取{{1} },1
或4
和1.0绘制四个数字之一。因此,我们可以通过获取0到1之间的(伪)随机数(2
)从arr
中随机抽样,然后确定p = rand
的第一个元素,{{1} } counts_cdf
:
[n, q]
在仿真模型中,顺便说一下,这是从离散概率分布生成伪随机变量的标准方法。
在绘制对的第二个随机数之前,我们需要修改p <= q
以反映无法再次绘制第一个数字的事实。假设将有许多对随机生成,最有效的是构造一个哈希def draw_random(cdf)
p = rand
cdf.find { |n,q| p <= q }.first
end
draw_random(counts_cdf) #=> 1
draw_random(counts_cdf) #=> 4
draw_random(counts_cdf) #=> 1
draw_random(counts_cdf) #=> 1
draw_random(counts_cdf) #=> 2
draw_random(counts_cdf) #=> 3
,其键是为该对随机绘制的第一个值,其值是相应的cdf。
cdf_first
例如,如果为该对的第一个元素绘制了cdf_second
,则为第二个元素cdf_second = counts.keys.each_with_object({}) { |n, h|
h[n] = cdf(arr.size - counts[n], counts.reject { |k,_| k==n }) }
#=> {1=>[[4, 0.25], [2, 0.75], [3, 1.0]],
# 4=>[[1, 0.5], [2, 0.833], [3, 1.0]],
# 2=>[[1, 0.6], [4, 0.8], [3, 1.0]],
# 3=>[[1, 0.5], [4, 0.667], [2, 1.0]]}
绘制2
的概率为0.6
绘制1
或0.8
和1
绘制4
,1.0
或1
。
然后我们可以按如下方式对一对进行采样。
4
和以前一样,要使用替换来采样3
值,我们执行
def sample_one_pair(cdf_first, cdf_second)
first = draw_random(cdf_first)
[first, draw_random(cdf_second[first])]
end
答案 2 :(得分:1)
通过替换,您可能会得到以下结果:
unique_pairs([1, 1, 2, 2, 3, 4]) # => [[4, 1], [1, 2], [1, 3]]
请注意1
被选中三次,即使它仅在原始数组中两次。这是因为1
被替换了#34;每次选择它。换句话说,它可以放回到集合中,可能会再次被选中。
这是Cary优秀的sample_one_pair解决方案没有替换的版本:
def unique_pairs(arr)
dup = arr.dup
Array.new(dup.size / 2) do
dup.shuffle!
first = dup.pop
second_index = dup.rindex { |e| e != first }
raise StopIteration unless second_index
second = dup.delete_at(second_index)
[first, second]
end
rescue StopIteration
retry
end
unique_pairs([1, 1, 2, 2, 3, 4]) # => [[4, 3], [1, 2], [2, 1]]
这可以通过创建原始数组的副本并在选择时删除元素(因此无法再次选择)。如果无法生成正确数量的对,则进行救援/重试。例如,如果首先选择[1, 3]
,然后选择[1, 4]
,则无法生成三个唯一对,因为[2, 2]
就是剩下的所有;样本空间已用完。
这应该比Cary的解决方案(更换时间)慢,但比需要循环和重试的已发布解决方案(无需替换)更快(平均)。 Welp,粉笔另一个指向&#34;总是基准!&#34;关于 所有 我的大多数假设我都错了。以下是我的机器上有16个数字([1, 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7, 8, 9, 9, 10]
)数组的结果:
cary_with_replacement
93.737k (± 2.9%) i/s - 470.690k in 5.025734s
mwp_without_replacement
187.739k (± 3.3%) i/s - 943.415k in 5.030774s
mudasobwa_without_replacement
129.490k (± 9.4%) i/s - 653.150k in 5.096761s
编辑:我已经更新了上述解决方案,以解决Stefan的众多问题。事后看来,错误是显而易见的,令人尴尬!从好的方面来说,修改后的解决方案现在比mudasobwa的解决方案更快,我已经证实这两种解决方案具有相同的偏见。
答案 3 :(得分:-1)
你可以检查是否有任何遗骸并再次洗牌:
takePhoto() {
const options: CameraOptions = {
quality: 50,
targetHeight: 600,
targetWidth: 600,
destinationType: this.camera.DestinationType.DATA_URL,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE
}
this.camera.getPicture(options).then((imageData) => {
let base64Image = 'data:image/jpeg;base64,' + imageData;
const pictures=storage().ref(`ProfilePictures/${this.myUid}`);
pictures.putString(base64Image, `data_url`);
}, (err) => {
}).present();
});
}
不太可能,请注意无限循环的可能性