Есть ли в C # встроенный способ преобразования двоичного числа в массив разрядностей (например, 0b1101 -> {0, 2, 3} )?

#c# #binary #set

#c# #двоичный #установить

Вопрос:

(Редактировать — предисловие: я реализую итерацию по всем подмножествам заданного размера. Для получения следующей комбинации я использую hack Госпера, чтобы быстро получить вектор 0/1 лексикографически следующей комбинации. Теперь мне нужно быстро сопоставить вектор комбинации с массивом элементов из моего набора. К счастью, элементы такие же, как и степени отдельных битов, и мне интересно, нет ли в C # быстрого ярлыка для этого.)

Если я получу K-е подмножество (в лексикографическом порядке) чисел 0 — (N-1), биты в двоичном представлении K сообщают мне, какие элементы я должен выбрать. Каков наиболее элегантный способ проверки того, какие биты установлены, и создания подмножества (массива) на их основе?

Что-то вроде:

 var BitPowers = new List<int>();
for(int i = 0; i<N;   i)
{
  if((K amp; (1<<i)) != 0)
  { 
   BitPowers.Add(i);
  }
}
return BitPowers.ToArray();
 

вероятно, было бы достаточно, но это лучший способ? Я предполагаю, что битовые операции выполняются быстро, но поскольку количество возможных наборов экспоненциально, оптимизация этой функции настолько, насколько я могу, была бы идеальной.

Комментарии:

1. Ничего встроенного, но вы можете написать свой собственный и опубликовать его в code-review, чтобы узнать, могут ли люди улучшить его. — Кстати: чтобы «оптимизировать», вам нужно решить, для чего оптимизировать: скорость, пространство, элегантность, удобство обслуживания …? — Также: _ число возможных множеств экспоненциально_ не уверен, что это значит ..?

Ответ №1:

Насколько я знаю, для этого нет встроенного API .NET.

Магия Linq

Вы можете написать этот компактный код за одно назначение, но менее оптимизированный по скорости:

 int value = 0b10110010;

var BitPowers = Convert.ToString(value, 2)
                       .Reverse()
                       .Select((bit, index) => new { index, bit })
                       .Where(v => v.bit == '1').Select(v => v.index);

foreach ( int index in BitPowers )
  Console.WriteLine(index);
 

Он преобразует целое число в двоичное представление строки, инвертированное для получения хороших индексов слева направо, затем выбирает пару (бит, индекс), затем фильтрует те, которые определены, затем выбирает индексы для создания перечислимого списка.

Вывод

 1
4
5
7
 

Компромисс между элегантностью и скоростью

Вы можете упростить свой цикл, используя экземпляр BitArray.

Возможно, это самый близкий «встроенный» способ, о котором вы просите:

 var bits = new BitArray(BitConverter.GetBytes(value));
for ( int index = 0; index < bits.Length; index   )
  if ( bits[index] )
    BitPowers.Add(index);
 

Комментарии:

1. Довольно круто, работает в 2 раза быстрее. (Проверено на 1 000 000 случайных чисел, 200 раз)