#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 раз)