Перестановка двух & ldquo; связанных & rdquo; списки в питоне

Удобный построитель строк для 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)

1
задан ritualmagick 21 January 2019 в 11:34
поделиться

1 ответ

Я не уверен на 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 из них (сначала преобразуйте списки в кортежи, чтобы сделать их хешируемыми), или получить решения для первого байта (или лучше: наиболее «сбалансированный», имеющий наименьшее количество решений для начала), а затем проверьте, какие из них также решают другие.

0
ответ дан tobias_k 21 January 2019 в 11:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: