Как выпустить неиспользованную способность строки

То, что вы ищете, это декартово произведение . По сути, это дает все возможные комбинации двух входов списка. К счастью, библиотека Python itertools имеет встроенный класс product, который может выступать в качестве итератора. Итак, теперь мы хотим сделать это в 3 шага:

  1. Разобрать строку
  2. Сгенерировать декартово произведение
  3. Восстановить строку

[1110 ] 1. Разобрать строку

Поскольку я предполагаю, что вы можете иметь любое количество {x:y} с, мы будем использовать цикл while

def parse_string(string): 
    index_of_ = string.find ("_")
    name = string [:index_of_]
    if index_of_ == -1: return name, []
    ranges = []
    while index_of_ != -1:  # still an _
        next_underscore = string.find ("_", index_of_ + 1)
        if next_underscore == -1:  # last underscore
            range_ = string [index_of_ + 1:]
        else: range_ = string [index_of_ + 1:next_underscore]
        start = range_ [1 : range_.find (":")]
        end = range_ [range_.find (":") + 1 : -1]
        ranges.append (tuple (range (int (start), int (end) + 1)))  # put all those numbers in
        if next_underscore == -1: break
        else: index_of_ = next_underscore
    return name, ranges

Эта функция зацикливает строку, извлекает имя и итеративно находит диапазоны. Он возвращает имя и список всех диапазонов, поэтому для вашего примера - NAME, [(1, 2), (3, 4, 5)]

2. Генерация комбо

Теперь, когда у нас есть список всех диапазонов, давайте получим декартово произведение этого списка.

from itertools import product   
    def generate_combos(ranges): 
        return product (*ranges)  # unpack the list

Это просто помогает нам передать список в product, который выполняет всю тяжелую работу.

3. Генерация строки

Здесь нам нужна функция для объединения двух других. Сначала он анализирует строку, чтобы получить диапазоны и имя. Затем для каждой комбинации декартового произведения он итеративно добавляет цифру к имени, а затем сохраняет результат:

def generate_string(string): 
    name, ranges = parse_string (string)
    results = []
    for combo in generate_combos (ranges):
        result = name
        for num in combo: 
            result += f"_{num}"
        results.append (result)
    return results

Пример:

print (generate_string ("NAME_{1:2}_{3:5}"))

Дает:

['NAME_1_3', 'NAME_1_4', 'NAME_1_5', 'NAME_2_3', 'NAME_2_4', 'NAME_2_5']

6
задан lc. 11 April 2009 в 12:55
поделиться

8 ответов

When you call reserve, you're making a request to change the capacity. Implementations will only guarantee that a number equal to or greater than this amount is reserved. Therefore, a request to shrink capacity may be safely ignored by a particular implementation.

However, I encourage you to consider whether this isn't premature optimization. Are you sure that you're really making so many strings that it's a memory bottleneck for you? Are you sure that it's actually memory that's the bottleneck?

From the documentation for reserve:

This can expand or shrink the size of the storage space in the string, although notice that the resulting capacity after a call to this function не обязательно равен res_arg но может быть как равным, так и большим чем res_arg , поэтому сокращается запросы могут или не могут произвести фактическое сокращение выделенных пространство в определенной библиотеке реализация. В любом случае, это никогда обрезает содержимое строки (для этого в целях изменения размера или очистки, изменить содержание).

12
ответ дан 8 December 2019 в 03:28
поделиться

Почему бы вам тогда не использовать массив символов?

5
ответ дан 8 December 2019 в 03:28
поделиться

Изложение ответа Навина :

string x = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
cerr << x.capacity() << "\n";    // MSVC++: 63    g++: 52

// This tends not to work (although in theory it could):
//x = "XYZ";
//cerr << x.capacity() << "\n";  // MSVC++: 63    g++: 52

// This tends to work (although in theory it might not):
string("XYZ").swap(x);
cerr << x.capacity() << "\n";    // MSVC++: 15    g++: 3

Обратите внимание, что если базовый распределитель выделяет больше, чем n байт при построении строки длины n (например, путем округления до ближайшего 32, как это делает MSVC ++), нет способа сделать он использует меньше байтов . Но вы, вероятно, не захотите делать это в любом случае, так как это «округление» сделано для того, чтобы сделать процесс динамического выделения памяти более эффективным, а также побочным эффектом ускорения конкатенации коротких строк в среднем (поскольку требуется меньше перераспределений). произойти).

4
ответ дан 8 December 2019 в 03:28
поделиться

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

3
ответ дан 8 December 2019 в 03:28
поделиться

Try the std::string swap-trick to shrink your strings:

std::string( str.data(), str.size() ).swap( str ) 

Where str is the string you want to cut down to size.

4
ответ дан 8 December 2019 в 03:28
поделиться

В основном это зависит от реализации. Идея состоит в том, чтобы минимизировать запросы выделения и фрагментации памяти. Легко доказать, что, удваивая существующий размер при каждом расширении блока, количество выделений и фрагментация памяти сводятся к минимуму. Поэтому, как правило, реализации контейнера STL удваивают существующий блок при расширении.

Одна вещь, которую вы можете сделать, это использовать собственный распределитель, который не будет выделять больше, чем необходимо, затем создайте свой std ::

1
ответ дан 8 December 2019 в 03:28
поделиться

емкость НИКОГДА не будет меньше 15 с dinkumware STL. std :: basic_string имеет объединение, которое является указателем на выделенный буфер или 16-байтовый буфер (если Capacity () <= 15) (для строковых символов)

, смотрите файл заголовка xstring

в приведенном вами примере где вы резервируете 16, вы фактически резервируете 17 (один для нуля), который> 16, поэтому он размещается, а не кэшируется в 16 байтах в объединении указателей кэша. Это распределение удваивает предыдущий размер (16), так что вы получите 32. Емкость этой строки тогда, вероятно, равна 31.

Но это зависит от реализации STL.

Изменение параметра шаблона распределителя в шаблоне decl из std :: basic_string НЕ достаточно - выбор того, когда выделять и сколько, находится в std :: basic_string; алгоритм роста НЕ в распределителе. Удвоение предыдущего размера (и сокращение при <

0
ответ дан 8 December 2019 в 03:28
поделиться

Не существует гарантированной минимальной емкости для std :: string . Вы можете запросить любую емкость, которую хотите, вызвав резерв , но конкретная реализация гарантирует только установку емкости на некоторое количество, большее или равное запрошенному размеру.

Вот модифицированная версия вашей программы, которая тестирует несколько методы сжатия строк:

#include <string>
#include <iostream>
using namespace ::std;

template< typename S >
S & reserve_request( S & s, typename S::size_type n ) {
    s.reserve( n ); return s;
}

template< typename S >
S & shrink_request1( S & s ) { s.reserve(); return s; }

template< typename S >
S & shrink_request2( S & s ) { S( s ).swap( s ); return s; }

template< typename S >
S & shrink_request3( S & s ) { S( s.c_str() ).swap( s ); return s; }

template< typename S >
void test( S & s ) { cout << s.capacity() << endl; }

int main() {
    string temp = "1234567890123456";    // length 16
    string str;

    test( str );                         // 15
    test( reserve_request( str, 16 ) );  // 31
    test( str += temp );                 // 31
    test( reserve_request( str, 16 ) );  // 31
    test( shrink_request1( str ) );      // 31
    test( shrink_request2( str ) );      // 31
    test( shrink_request3( str ) );      // 31
    return 0;
}

Может показаться, что std :: string Visual C ++ обычно сохраняет некоторую свободную емкость.

Если ваш проект загружает большое количество строк, считанных из внешнего источника, размер которого затем никогда не меняется, вам может быть лучше (как другие предлагали) хранить их в одном большом блоке символьной памяти, разделенном символами '\ 0' (то есть в виде C-строк). Если хочешь, Вы можете предоставить функции-оболочки, которые возвращают std :: string s на лету.

0
ответ дан 8 December 2019 в 03:28
поделиться
Другие вопросы по тегам:

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