Я хочу преобразовать массив [3, 4, 8]
→ [3, 4, 8, 34, 38, 48, 43, 83, 84, 348, 384, 834, 843, 438, 483]
Я пробовал array.permutation
, но это только возвращается [348, 384, 834, 843, 438, 483]
. Есть ли чистый способ сделать это без предварительного создания всех возможных подмножеств?
🤔 А знаете ли вы, что...
В Ruby все является объектом, включая числа и функции.
Array#permutation принимает один необязательный параметр, указывающий, какой максимальный размер перестановки нужно создать.
В вашем случае вам просто нужны все перестановки размера 1
, затем 2
, затем 3
,... до вашего input.count
.
Итак, это так же просто, как создать диапазон этих чисел, сопоставить их, каждый раз вызывая permutation
с другим номером и комбинируя результаты:
def all_permutations_of(input)
(1..input.count).flat_map do |permutation_length|
input.permutation(permutation_length).to_a
end
end
p all_permutations_of([3, 4, 8])
# => [
# [3], [4], [8],
# [3, 4], [3, 8], [4, 3], [4, 8], [8, 3], [8, 4],
# [3, 4, 8], [3, 8, 4], [4, 3, 8], [4, 8, 3], [8, 3, 4], [8, 4, 3],
# ]
И если вы хотите, чтобы эти цифры были реальными числами, как показано в вашем примере, вам понадобится небольшая функция для их объединения, например, эта, которую я ласково называю «сглаживание»:
# Produces a single number from an array of digits
# E.g. `[1, 2, 3]` becomes `123`
def smoosh(digits)
exponent = digits.count
digits.sum do |digit|
exponent -= 1
digit * (10 ** exponent)
end
end
p all_permutations_of([3, 4, 8]).map { smoosh(_1) }
# => [3, 4, 8, 34, 38, 43, 48, 83, 84, 348, 384, 438, 483, 834, 843]
Вы можете объединить перестановки каждого размера вместе, а затем превратить их в массив:
ary = [3, 4, 8]
Enumerator::Chain.new(
*ary.map.with_index(1) { ary.permutation(_2) }
).map(&:join).map(&:to_i)
#=> [3, 4, 8, 34, 38, 43, 48, 83, 84, 348, 384, 438, 483, 834, 843]