Блог пользователя ilyaraz

Автор ilyaraz, 15 лет назад, По-русски

Обнаружил сегодня забавный момент в Python'е.

Представьте себе, что у вас есть список списков x. Например, x = [[1, 2, 3], [], [[6, 6, 6]]]. Мы хотим сконкатенировать все элементы x и получить в данном случае [1, 2, 3, [6, 6, 6]]. Наука это учит делать красиво: sum(x, []). Действительно, сложение для списков -- это просто-напросто конкатенация.

Однако, у данного подхода есть существенный недостаток. Если, к примеру, у нас k списков константной длины, то sum(x, []) будет работать за время O(k2), а не O(k), как разумеется хотелось бы. Это происходит вот почему: результат сложения списков записывается в новое место, и на выделение памяти каждый раз уходит линейное время. Проблема. Однако, простой цикл спасает положение.

result = []
for element in x: <перенос строки + таб> for item in element: <перенос строки + таб + таб> result.append(item)

Действительно, append работает за учетное время O(1).

Внимание, бонусный вопрос: как сделать конкатенацию всех элементов за время O(k) в "функциональном" стиле?

  • Проголосовать: нравится
  • 0
  • Проголосовать: не нравится

15 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    Наверное, это будет за линейное время работать. Правда, мне не нравится, что chain будет передаваться k аргументов, но кто его знает, как это в Python реализовано -- может все и будет хорошо.
  • 15 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится
    Пожалуй, выглядит симпатичнее всего в итоге list(itertools.chain.from_iterable(x)).
15 лет назад, скрыть # |
Rev. 2  
Проголосовать: нравится 0 Проголосовать: не нравится
result.extend(element)