У меня есть большие наборы данных, которые необходимо отфильтровать корневые пакеты, как показано ниже:
Чтобы повысить производительность, я добавляю столбец flag
, чтобы отслеживать, обработано оно или нет.
Звучит так, будто теперь большое О — это n, а не n квадрат. что-нибудь мы можем улучшить?
Очевидным является второй цикл for, теперь используйте продолжение пропуска предыдущих элементов, может быть, это лучше сделать?
import re
import pandas as pd
import tabulate
def dumpdf(df):
if len(df) == 0: return
df = df.reset_index(drop=True)
tab = tabulate.tabulate(df, headers='keys', tablefmt='psql',showindex=True)
print(tab)
return
def main():
data = [
['A','com.example'],
['A','com.example.a'],
['A','com.example.b.c'],
['A','com.fun'],
['B','com.demo'],
['B','com.demo.b.c'],
['B','com.fun'],
['B','com.fun.e'],
['B','com.fun.f.g']
]
df = pd.DataFrame(data,columns=['name','package'])
df ['flag'] = None
df = df.sort_values(by = "package", key=lambda x: x.str.len()).reset_index(drop=True)
for idx,row in df.iterrows():
if row['flag'] == None:
df.loc[idx,'flag'] = True
for jdx, jrow in df.iterrows():
if jdx <= idx: continue
if row['name'] == jrow['name']:
if jrow['package'].startswith(row['package']):
df.loc[jdx,'flag'] = False
#
df = df[df['flag']]
df = df.groupby('name',as_index=False).agg({'package':'\n'.join})
dumpdf(df)
return
main()
IIUC вы можете сделать:
from functools import cmp_to_key
from itertools import groupby
def fn(g):
out = []
for _, k in groupby(g.sort_values(), cmp_to_key(lambda a, b: not b.startswith(a))):
out.append(next(k))
return pd.Series(out)
out = df.groupby("name")["package"].apply(fn).droplevel(1).reset_index()
print(out)
Распечатки:
name package
0 A com.example
1 A com.fun
2 B com.demo
3 B com.fun
@beetlej Да, так что n log n
Хороший ответ, это очень быстро. это линейная сложность?