2015-08-14 3 views
1

Допустим, у меня есть целое число 98. Двоичное представление этой строки будет:рубин Преобразование целого числа в двоичном до целого массива установленных битов

(98).to_s(2) # 1100010 

Теперь я хочу, чтобы преобразовать эту бинарную строку в целое число массив всех битов, которые установлены. Это дало бы мне:

[64,32,2] 

Как бы я это сделал?

Обновление: Преобразование массива int в int необязательно должно включать String, это то, что я знал. Я предполагаю, что не строковые операции также будут быстрее.

Ruby удивительно, видя все эти различные способы справиться с этим!

ответ

6

Это будет работать:

i = 98 
(0...i.bit_length).map { |n| i[n] << n }.reject(&:zero?) 
#=> [2, 32, 64] 
  • Fixnum#bit_length возвращает позицию самого высокого "1" бит
  • Fixnum#[n] возвращает целое в п й бит, т.е. 0 или 1
  • Fixnum#<< сдвиги бит влево. 1 << n эквивалентно 2 п

Шаг за шагом:

(0...i.bit_length).map { |n| i[n] } 
#=> [0, 1, 0, 0, 0, 1, 1] 

(0...i.bit_length).map { |n| i[n] << n } 
#=> [0, 2, 0, 0, 0, 32, 64] 

(0...i.bit_length).map { |n| i[n] << n }.reject(&:zero?) 
#=> [2, 32, 64] 

Вы можете reverse результат.

+1

Это будет не только работать, но и намного чище, чем идти через 'String', как и другие примеры. –

+0

неопределенный метод 'bit_length» 98: Fixnum Я не на последней версии Ruby, так что это не похоже на работу Руби 2.0.0p353 – mahatmanich

+0

@mahatmanich 'bit_length' был введен в Рубине 2.1 – Stefan

2

Вот несколько способов:

# 1

s = (98).to_s(2) 
sz = s.size-1 
s.each_char.with_index.with_object([]) { |(c,i),a| a << 2**(sz-i) if c == '1' } 
    # => [64, 32, 2] 

# 2

n = 2**(98.to_s(2).size-1) 
arr = [] 
while n > 0 
    arr << n if 90[n]==1 
    n /= 2 
end 
arr 
    #=> [64, 32, 2] 
2
(98).to_s(2).reverse.chars.each_with_index. 
    map {|x,i| x=="1" ? 2**i : nil }.compact.reverse 

Уф! Давайте разберем, что вниз:

  • сначала получить бинарную строку в качестве примера (98).to_s(2)

  • Нам нужно начать 0-индекс с правой стороны, а следовательно .reverse

  • .chars.each_with_index дает нам пары например [ '1', 4 ] для символа в позиции бита

  • .map преобразует символы «1» в их положение alue 2 ** i (т. 2 к силе тока битовой позиции) и «0» в nil так что он может быть удален

  • .compact отбросить nil значения, которые вы не хотите

  • .reverse иметь убывающие степени 2, как ваш пример

+0

«.map преобразует символы« 1 »в их значение 2 ** i и« 0 »в нуль, чтобы его можно было удалить» Можете ли вы подробно остановиться на этом? что делает 2 ** я? – mahatmanich

+1

Это просто возведение в степень, т. Е. «X ** y» равно «x до степени y». –

+0

Фу! Почему нужен первый разворот? – mahatmanich

2

Обратный текст, сопоставьте его с двоичным кодом значений каждой цифры, отклоните нули. Опционально переверните его снова.

s.reverse.chars.map.with_index{ |c, i| c.to_i * 2**i }.reject{ |b| b == 0 }.reverse 

Или вы можете нажать значения в массив с each_with_index

a = [] 
s.reverse.each_with_index do |c, i| 
    a.unshift c.to_i * 2**i 
end 

, что, вероятно, быстрее и более удобным для чтения, но менее идиоматическое.

+1

Какая версия или библиотека Ruby предоставляет вам '.map' на' String' здесь? Это не ядро ​​Ruby –

+0

Вы правы, fixt. – Borsunho

+0

Аккуратно, не знал о модификаторе '.with_index'. –

Смежные вопросы