2013-10-27 1 views
3

Это относится к моему предыдущему вопросу: Converting from nested lists to a delimited stringуборщик метода списка понимание очистки

У меня есть внешний сервис, который отправляет данные нам в формате с разделителями строк. Это списки предметов, глубиной до 3 уровней. Уровень 1 делится на '|'. Уровень 2 делится на ';' а уровень 3 делится на «,». Каждый уровень или элемент может содержать 0 или более элементов. Упрощенный пример:
a,b;c,d|e||f,g|h;;

У нас есть функция, которая преобразует это вложенные списки, которые, как она манипулирует в Python.

def dyn_to_lists(dyn): 
    return [[[c for c in b.split(',')] for b in a.split(';')] for a in dyn.split('|')] 

Для приведенного выше примера, эта функция приводит к следующему:

>>> dyn = "a,b;c,d|e||f,g|h;;" 
>>> print (dyn_to_lists(dyn)) 
[[['a', 'b'], ['c', 'd']], [['e']], [['']], [['f', 'g']], [['h'], [''], ['']]] 

Для списков, на любом уровне, только один пункт, мы хотим, чтобы это как скаляр, а не список на 1 пункт , Для пустых списков мы хотим, чтобы они были пустой строкой. Я пришел с этой функцией, которая делает работу:

def dyn_to_min_lists(dyn): 
    def compress(x): 
     return "" if len(x) == 0 else x if len(x) != 1 else x[0] 

    return compress([compress([compress([item for item in mv.split(',')]) for mv in attr.split(';')]) for attr in dyn.split('|')]) 

С помощью этой функции и с помощью приведенного выше примера, он возвращает (* см обновление ниже):

[[['a', 'b'], ['c', 'd']], 'e', '', ['f', 'g'], ['h', '', '']] 

Будучи новым для Python, я не уверен, что это лучший способ сделать это. Есть ли более чистые способы справиться с этим?

Это потенциально может иметь большое количество данных, проходящих через него, есть ли более эффективные/масштабируемые способы достижения этого?

Update

Я нашел ошибку в моей первоначальной функции компресса. Если внутренний список содержит более одного элемента, внешний список не может быть удален - это приведет к тому, что преобразование будет необратимым. Для этого, я обновил @ функции компресса в Blender быть:

def __compress(x): 
    if len(x) > 1: 
     return x 
    elif not x: 
     return '' 
    else: 
     if type(x[0]) != list: 
      return x[0] 
     else: 
      return x 

Теперь он возвращает правильный вывод:

[[['a', 'b'], ['c', 'd']], 'e', '', [['f', 'g']], ['h', '', '']] 
+0

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

+0

Спасибо @akonsu, хотел начать с чего-то, что работает, а затем работать над улучшением его оттуда. Я изучаю другие способы в Python для достижения этого. Я обновлю Q, если я получу что-нибудь лучше. –

+0

@akonsu - любые ссылки, которые могут вам помочь? –

ответ

1

Вы можете сделать несколько вещей, чтобы ускорить его:

  • Избавиться от понимания по большинству мест: [item for item in mv.split(',')] будет mv.split(','). Это бесполезно.
  • Перемещение функции compress вне функции dyn_to_min_lists. Вы не хотите, чтобы он создавался каждый раз при запуске dyn_to_min_lists.
  • Использование правдивости происходит быстрее, чем вызов len, поэтому замените len(x) == 0 на not x.
  • Переупорядочение условий вашей функции compress, так что чаще появятся первые случаи, которые ускорят работу.

Так полученный код:

def compress(x): 
    if len(x) > 1: 
     return x 
    elif not x: 
     return '' 
    else: 
     return x[0] 

def parse(s): 
    return compress([ 
     compress([ 
      compress(b.split(',')) for b in a.split(';') 
     ]) for a in s.split('|') 
    ]) 

Вот сравнение скорости:

>>> %timeit parse('a,b;c,d|e||f,g|h;;') 
100000 loops, best of 3: 10 µs per loop 
>>> %timeit dyn_to_min_lists('a,b;c,d|e||f,g|h;;') 
10000 loops, best of 3: 15.6 µs per loop 

Это около 36% быстрее на моем компьютере. Если это действительно важная часть вашего скрипта, реализуйте его на C и скомпилируйте его в расширение C.

+0

Отлично. Спасибо Блендер. Он по-прежнему обрабатывает строку 3 раза, поэтому, хотя ваша версия намного лучше, мой общий алгоритм для этого довольно ужасен. Раньше я еще не писал никаких C-расширений для Python, хотя я сделал достаточно программирования на C, и я, вероятно, должен был бы изучить его. Спасибо за направление. –

Смежные вопросы