我正在尝试编写一个将'abcd'作为输入的方法,然后返回:
["a b c d", "a b cd", "a bc d", "a bcd", "ab c d", "ab cd", "abc d", "abcd"]
所以,所有可能的方法将字符串拆分为n个子串,当你连接s1 + s2 + s3 +时......你会收回原始字符串。
我已经解决了这个问题,但我觉得应该有一种更快,更直接的方法。
def sequence(n)
[true, false].repeated_permutation(n).to_a
end
def breakdown4(string)
guide = sequence(string.length-1)
arr = []
guide.each do |i|
s = string.dup
counter = 0
i.each do |j|
if j
s.insert(counter+1, " ")
p counter
counter += 2
else
counter += 1
end
end
arr.push(s)
end
arr
end
有什么建议吗?
答案 0 :(得分:5)
oneliner也使用repeated_permutation
(我刚从你那里学到: - ):
s = 'abcd'
[' ', ''].repeated_permutation(s.size - 1).map { |j| s.chars.zip(j).join }
=> ["a b c d", "a b cd", "a bc d", "a bcd", "ab c d", "ab cd", "abc d", "abcd"]
repeated_permutation
生成关节,例如[" ", "", " "]
。zip
将它们与字母配对,例如[["a", " "], ["b", ""], ["c", " "], ["d", nil]]
。join
将所有部分转换为字符串并加入它们,例如"a bc d"
。(请注意nil
成为空字符串,join
works recursively,有效地展平了整个结构。
在我知道repeated_permutation
之前我想出了以前的解决方案:
[s[0]].product(*s[1..-1].chars.flat_map { |c| [[' ', ''], [c]] }).map(&:join)
=> ["a b c d", "a b cd", "a bc d", "a bcd", "ab c d", "ab cd", "abc d", "abcd"]
s[1..-1].chars.reduce([s[0]]) { |m, c| m.product([' ', ''], [c]) }.map(&:join)
=> ["a b c d", "a b cd", "a bc d", "a bcd", "ab c d", "ab cd", "abc d", "abcd"]
[''].product(*([[' ', '']] * s.size.pred)).map { |j| s.gsub('') { j.shift } }
=> ["a b c d", "a b cd", "a bc d", "a bcd", "ab c d", "ab cd", "abc d", "abcd"]
(0...2**s.size).step(2).map { |i| s.gsub(/(?!^)/) { ' ' * (1 & i /= 2) } }
=> ["abcd", "a bcd", "ab cd", "a b cd", "abc d", "a bc d", "ab c d", "a b c d"]
所有这些的基本思想是这样的(为了清楚起见使用硬编码字符串):
['a'].product([' ', ''], ['b'], [' ', ''], ['c'], [' ', ''], ['d']).map(&:join)
=> ["a b c d", "a b cd", "a bc d", "a bcd", "ab c d", "ab cd", "abc d", "abcd"]
答案 1 :(得分:4)
s = 'abcd'
s[1..-1].each_char.reduce([s[0]]) do |arr, c|
space_c = " #{c}"
arr.flat_map { |str| [str + c, str + space_c] }
end
# => ["abcd", "abc d", "ab cd", "ab c d", "a bcd", "a bc d", "a b cd", "a b c d"]
这是另一种方式(在字符串中填充空格)。
arr = (1..s.size-1).to_a
#=> [1, 2, 3]
s.size.times.flat_map do |n|
arr.combination(n).map do |locs|
scopy = s.dup
locs.reverse_each { |idx| scopy.insert(idx, ' ') }
scopy
end
end
#=> ["abcd", "a bcd", "ab cd", "abc d", "a b cd", "a bc d", "ab c d", "a b c d"]
答案 2 :(得分:3)
以下是不同方法之间的一些比较:
#navid
def sequence(n)
[true, false].repeated_permutation(n).to_a
end
def breakdown4(string)
guide = sequence(string.length-1)
arr = []
guide.each do |i|
s = string.dup
counter = 0
i.each do |j|
if j
s.insert(counter+1, " ")
#p counter
counter += 2
else
counter += 1
end
end
arr.push(s)
end
arr
end
#tom
def powerset(arr)
a = [[]]
for i in 0...arr.size do
len = a.size; j = 0;
while j < len
a << (a[j] + [arr[i]])
j+=1
end
end
a
end
def breakdown(string)
indexes_lists = powerset((1..string.length-1).to_a)
indexes_lists.map(&:reverse).map do |indexes_list|
result = string.dup
indexes_list.each { |i| result.insert(i, " ")}
result
end
end
#stefan
def stefan1 s
[s[0]].product(*s[1..-1].chars.flat_map { |c| [[' ', ''], [c]] }).map(&:join)
end
def stefan2 s
s[1..-1].chars.reduce([s[0]]) { |m, c| m.product([' ', ''], [c]) }.map(&:join)
end
def stefan3 s
[''].product(*([[' ', '']] * s.size.pred)).map { |j| s.gsub('') { j.shift } }
end
def stefan4 s
(0...2**s.size).step(2).map { |i| s.gsub(/(?!^)/) { ' ' * (1 & i /= 2) } }
end
def stefan5 s
[' ', ''].repeated_permutation(s.size - 1).map { |j| s.chars.zip(j).join }
end
#cary
def cary s
s[1..-1].each_char.reduce([s[0]]) do |arr, c|
space_c = ' ' + c
arr.flat_map { |str| [str + c, str + space_c] }
end
end
#cary2
def cary2 s
arr = (1..s.size-1).to_a
#=> [1, 2, 3]
s.size.times.flat_map do |n|
arr.combination(n).map do |locs|
scopy = s.dup
locs.reverse_each { |idx| scopy.insert(idx, ' ') }
scopy
end
end
end
结果
require 'fruity'
str = 'abcd'
compare do
navid { s = str.dup; breakdown4(s) }
tom { s = str.dup; breakdown(s).sort }
stefan_1 { s = str.dup; stefan1(s) }
stefan_2 { s = str.dup; stefan2(s) }
stefan_3 { s = str.dup; stefan3(s) }
stefan_4 { s = str.dup; stefan4(s).sort }
stefan_5 { s = str.dup; stefan5(s) }
cary_s { s = str.dup; cary(s).reverse }
cary_s2 { s = str.dup; cary2(s).sort }
end
#Running each test 64 times. Test will take about 1 second.
#cary_s is faster than navid by 2x ± 1.0
#navid is similar to tom
#tom is similar to cary_s2
#cary_s2 is similar to stefan_1
#stefan_1 is similar to stefan_2
#stefan_2 is faster than stefan_3 by 2x ± 1.0
#stefan_3 is similar to stefan_5
#stefan_5 is similar to stefan_4
使用更长的字符串:
str = 'abcdefghijklm'
#Running each test once. Test will take about 4 seconds.
#cary_s is faster than stefan_1 by 9x ± 1.0
#stefan_1 is similar to cary_s2
#cary_s2 is similar to navid
#navid is similar to tom
#tom is similar to stefan_2
#stefan_2 is faster than stefan_3 by 2x ± 1.0
#stefan_3 is similar to stefan_5
#stefan_5 is similar to stefan_4
答案 3 :(得分:2)
这实际上是一个非常棘手的问题......但是在考虑了一下之后,我想出了一个聪明的方法。它可能不是最 compact (单线程)解决方案;但它很有启发性,很容易用任何语言改写,并且不浪费。
首先要认识到,给定长度为n
的输入字符串,有n-1
个可能插入空格的位置。所以,我们需要做的就是:
n-1
位置的所有可能组合,然后对于第(1)部分,我使用了(1..n-1).to_a
n
的简单算法,其中def powerset(arr)
a = [[]]
for i in 0...arr.size do
len = a.size; j = 0;
while j < len
a << (a[j] + [arr[i]])
j+=1
end
end
a
end
是输入字符串长度:
powerset([1,2,3])
#=> [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
例如:
def powerset(arr)
a = [[]]
for i in 0...arr.size do
len = a.size; j = 0;
while j < len
a << (a[j] + [arr[i]])
j+=1
end
end
a
end
def breakdown(string)
indexes_lists = powerset((1..string.length-1).to_a)
indexes_lists.map(&:reverse).map do |indexes_list|
result = string.dup
indexes_list.each { |i| result.insert(i, " ")}
result
end
end
现在,我们可以简单地在这些索引处向原始字符串插入空格。我添加的一个小技巧是从更大的索引开始,它不会弄乱其他索引 - 即你需要以降序使用每个列表。
这是最终的代码:
breakdown("abcde")
# => ["abcde", "a bcde", "ab cde", "a b cde", "abc de",
# "a bc de", "ab c de", "a b c de", "abcd e", "a bcd e",
# "ab cd e", "a b cd e", "abc d e", "a bc d e", "ab c d e",
# "a b c d e"]
用法:
git remote -v