Удобный построитель строк для c ++
Как и многие ранее ответившие, std :: stringstream - это метод выбора. Он работает хорошо и имеет множество вариантов преобразования и форматирования. IMO у него есть один довольно неудобный недостаток, хотя: вы не можете использовать его как один лайнер или как выражение. Вам всегда нужно писать:
std::stringstream ss;
ss << "my data " << 42;
std::string myString( ss.str() );
, что очень раздражает, особенно если вы хотите инициализировать строки в конструкторе.
Причина в том, что a) std :: stringstream не имеет оператора преобразования в std :: string и b) оператор & lt; () в строковом потоке не возвращают ссылку на строковый поток, а вместо этого ссылаются на std :: ostream reference, которая не может быть далее вычислена как потоковый поток.
Решение состоит в переопределении std :: stringstream и дать ему лучшие совпадающие операторы:
namespace NsStringBuilder {
template<typename T> class basic_stringstream : public std::basic_stringstream<T>
{
public:
basic_stringstream() {}
operator const std::basic_string<T> () const { return std::basic_stringstream<T>::str(); }
basic_stringstream<T>& operator<< (bool _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (char _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (signed char _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned char _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (short _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned short _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (int _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned int _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (long _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned long _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (long long _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (unsigned long long _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (float _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (double _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (long double _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (void* _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (std::streambuf* _val) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (std::ostream& (*_val)(std::ostream&)) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (std::ios& (*_val)(std::ios&)) { std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (std::ios_base& (*_val)(std::ios_base&)){ std::basic_stringstream<T>::operator << (_val); return *this; }
basic_stringstream<T>& operator<< (const T* _val) { return static_cast<basic_stringstream<T>&>(std::operator << (*this,_val)); }
basic_stringstream<T>& operator<< (const std::basic_string<T>& _val) { return static_cast<basic_stringstream<T>&>(std::operator << (*this,_val.c_str())); }
};
typedef basic_stringstream<char> stringstream;
typedef basic_stringstream<wchar_t> wstringstream;
}
При этом вы можете писать такие вещи, как
std::string myString( NsStringBuilder::stringstream() << "my data " << 42 )
даже в конструкторе.
Должен признаться, я не оценивал производительность, так как я не использовал ее в среде, которая еще больше использует строение, но я предполагаю, что это будет не намного хуже, чем std: : stringstream, так как все делается через ссылки (кроме преобразования в строку, но это операция копирования в std :: stringstream)
Я не уверен на 100%, понимаю ли я, что вы пытаетесь сделать здесь. Насколько я понимаю, вам нужны все перестановки позиций в исходном битовом массиве, которые дают целевой битовый массив.
Наивным подходом было бы генерировать все перестановки и затем проверять, какие из них соответствуют цели, но это были бы 8! = 40k
перестановки. Это не очень много, но может быть проблемой для более длинных последовательностей или при этом довольно часто. Кроме того, вы можете получить все перестановки для единиц и нулей и распределить их в соответствии с вашим результатом; в вашем примере это будет просто 5!*3! = 720
(более сбалансированный == меньше / лучше).
Примерно так (примечание: я просто использовал строку вместо BitArray, но здесь это не имеет значения)
>>> bits = "11100011"
>>> trgt = "11101100"
>>> ones = [i for i, e in enumerate(bits) if e == "1"]
>>> zeros = [i for i, e in enumerate(bits) if e == "0"]
>>> from itertools import permutations
>>> res = [[next(p1 if b == "1" else p2) for b in trgt] for p1, p2 in
... ((iter(p1), iter(p2)) for p1 in permutations(ones)
... for p2 in permutations(zeros))]
...
>>> res[0]
[0, 1, 2, 3, 6, 7, 4, 5]
>>> len(res)
720
>>> set(''.join(bits[i] for i in l) for l in res)
{'11101100'}
Это дает вам решение для одного байта. Теперь, если я правильно понял, что многобайтовая часть, вы ищете одно транспонирование битов, которое можно применить к всем байтам. В этом случае число решений действительно быстро станет меньше. Вы можете использовать вышеупомянутый алгоритм, чтобы получить все решения для отдельных байтов, а затем получить set.intersection
из них (сначала преобразуйте списки в кортежи, чтобы сделать их хешируемыми), или получить решения для первого байта (или лучше: наиболее «сбалансированный», имеющий наименьшее количество решений для начала), а затем проверьте, какие из них также решают другие.