Мне потребовался сценарий Python для сокращения списка значений, и я не был уверен, что это лучший способ выполнить sh. Приведенные ниже функции представляют собой набор различных подходов, которые были рекомендованы мне, и связанные с ними среды выполнения. Для справки, мои исходные данные для этих эталонных тестов использовали 100 списков приблизительно по 500 000 записей в каждом
Спасибо всем, кто указал мне правильное направление!
Пример ввода:
values = [3, 4, 4, 5, 3, 2, 7, 8, 9, 9, 9, 9, 9, 4, 4, 2, 1, 1]
Желаемый результат:
col_counts = [1, 2, 1, 1, 1, 1, 1, 5, 2, 1, 2]
col_values = [3, 4, 5, 3, 2, 7, 8, 9, 4, 2, 1]
Output String = 1*3 2*4 1*5 1*3 1*2 1*7 1*8 5*9 2*4 1*2 2*1
Сводные данные:
- Использование Pandas было очень по скорости аналогичен ручной итерации по списку
- Использование itertools с (k, len (list (g))) на самом деле 2x быстрее, чем ( k, сумма (1 для i in g)
- Использование itertools w / len было самым быстрым методом ( 5x быстрее, чем pandas или ручное l oop)
- Самый быстрый метод также был самым компактным: для построения выходной строки потребовалось всего 2 строки (против 28 в моем оригинале)
Код для быстрого метода:
def condense_values_2liner(values):
grouped_values = [(len(list(g)), k) for k,g in groupby(values)]
output_str = " ".join("%s*%s" % tup for tup in grouped_values)
return output_str
Полный код для других методов:
# BENCHMARKED PERFORMANCE (100 LISTS OF APPROX. 500,000 values
# > condense_values_loop = 21.7s
# > condense_values_pandas = 21.2s
# > condense_values_itertools_sum = 10.4s
# > condense_values_itertools_len = 5.1s
# > condense_values_2liner = 4.8s
# > condense_values_loop = 21.7s
def condense_values_loop(values):
prev_value = None
cnt = 0
value_counts = []
first = True
for value in values:
if first: # First value
cnt = 1
prev_value = value
first = False
else:
if value != prev_value:
value_counts.append([cnt,prev_value])
cnt = 1
prev_value = value
else:
cnt += 1
# Write final line to array (check for no values)
value_counts.append([cnt,value])
# Build output strings
output_pairs = []
for value_count in value_counts:
entry = str(value_count[0]) + "*" + str(value_count[1])
output_pairs.append(entry)
output_str = ' '.join(output_pairs)
return output_str
# > condense_values_pandas = 21.2s
def condense_values_pandas(values):
df = pd.DataFrame({'value': values})
df2 = (
df
.groupby(df['value'].ne(df['value'].shift()).cumsum())
.count()
.reset_index(drop=True)
.assign(x=df.loc[df['value'].ne(df['value'].shift()), 'value'].tolist())
)
df2.columns = ['counts', 'value']
df2['output_str'] = df2['counts'].astype(str) + '*' + df2['value'].astype(str)
col_counts = df2['counts'].tolist()
col_values = df2['value'].tolist()
output_string = ' '.join(df2['output_str'])
return output_string
# condense_values_itertools_sum = 10.4s
def condense_values_itertools_sum(values):
grouped_values = [(k, sum(1 for i in g)) for k,g in groupby(values)]
paired_values = []
for pair in grouped_values:
paired_values.append(str(pair[1]) + "*" + str(pair[0]))
output_str = ' '.join(paired_values)
return output_str
# condense_values_itertools_len = 5.1s
def condense_values_itertools_len(values):
grouped_values = [(k, len(list(g))) for k,g in groupby(values)]
paired_values = []
for pair in grouped_values:
paired_values.append(str(pair[1]) + "*" + str(pair[0]))
output_str = ' '.join(paired_values)
return output_str
# > condense_values_2liner = 4.8s
# > Note: 'join()' call required switching k/g from functions above
def condense_values_2liner(values):
grouped_values = [(len(list(g)), k) for k,g in groupby(values)]
output_str = " ".join("%s*%s" % tup for tup in grouped_values)
return output_str