Могу ли я рассчитывать на сохранение порядка в кортежей Python?
У меня есть список дат, из которых я хочу построить сегменты времени. Другими словами, поверните [t0, t1, ... tn]
в [(t0,t1),(t1,t2),...,(tn-1, tn)]
. Я сделал это так:
# start by sorting list of datetimes
mdtimes.sort()
# construct tuples which represent possible start and end dates
# left edges
dtg0 = [x for x in mdtimes]
dtg0.pop()
# right edges
dtg1 = [x for x in mdtimes]
dtg1.reverse()
dtg1.pop()
dtg1.sort()
dtsegs = zip(dtg0,dtg1)
Вопросы...
- Могу ли я рассчитывать на tn-1 < tn для любого (tn-1, tn) после того, как я создал их таким образом? (Сохраняется ли заказ?)
- Хорошо ли копировать исходный список
mdtimes
со списком? Если нет, то как это сделать?
-
Целью построения этих кортежей является их перебор и сегмент данных с tn-1
и tn
. Это разумный подход? то есть.
datasegment = [x for x in bigdata if ( (x['datetime'] > tleft) and (x['datetime'] < tright))]
Спасибо
Ответы
Ответ 1
-
Порядок набора состоит в том, что вы вставляете значения в кортеж. Они не будут сортироваться, как я думаю, вы спрашиваете. zip
снова сохранит порядок, в который вы ввели значения.
-
Это приемлемый метод, но у меня есть 2 альтернативных предложения: используйте модуль copy или используйте dtg1 = mdtimes[:]
.
-
Звучит разумно.
Ответ 2
Оба list
и tuple
упорядочены.
dtg0, dtg1 = itertools.tee(mdtimes)
next(dtg0)
dtsegs = zip(dtg0, dtg1)
Ответ 3
Вы можете достичь того же значения с помощью zip
:
>>> l = ["t0", "t1", "t2", "t3", "t4", "t5", "t6"]
>>> zip(l[::2], l[1::2])
[('t0', 't1'), ('t2', 't3'), ('t4', 't5')]
Ответ 4
Вместо: dtg0 = [x for x in mdtimes]
, dtg0 = mdtimes[:]
будет делать, так как вы просто копируете один список в другой. Примечание: начиная с Python 3.3 вы можете просто сказать newlist = oldlist.copy()
Как и для порядка, порядок zip
хорошо определен, и оба списка и кортежи - это упорядоченные коллекции, поэтому здесь не должно быть проблем.
Ответ 5
Поворот (x1, x2, x3,...) в [(x1, x2), (x2, x3),...] называется парной комбинацией, и он настолько распространен в шаблоне, что itertools содержит рецепт:
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
for ta, tb in pairwise(mdtimes):
....
Ответ 6
Это ответ на вопрос: "Это разумный подход?" (который, кажется, был проигнорирован всеми).
Резюме.. Вам может понадобиться/нужно поднять свой взгляд, сделав парную вещь из mdtimes
к охватывающей проблеме (сегментирование bigdata
).
деталь:
Желаемое использование результата выражается следующим образом:
datasegment = [x for x in bigdata if ( (x['datetime'] > tleft) and (x['datetime'] < tright))]
который лучше выражается как:
datasegment = [x for x in bigdata if tleft < x['datetime'] < tright]
Обратите внимание, что в этом случае он не будет включать случаи, когда метка времени точно равна одной из граничных точек, поэтому измените ее на:
datasegment = [x for x in bigdata if tleft <= x['datetime'] < tright]
Но это будет появляться в цикле:
for tleft, tright in dtsegs:
datasegment = [x for x in bigdata if tleft <= x['datetime'] < tright]
do_something_with(datasegment)
Упс! Это займет время, пропорциональное len(bigdata) * len(dtsegs)
... каковы вероятные значения len(bigdata)
и len(dtsegs)
?
Если bigdata
сортируется, то вы можете сделать это во времени пропорционально N
, где N = len(bigdata)
. Если bigdata
еще не отсортировано, его можно сортировать по времени, пропорциональному N * log(N)
.
Вам может потребоваться задать еще один вопрос...
Также стоит отметить, что любые элементы в bigdata
, имеющие временную метку < min (mdtimes) или >= max (mdtimes) не будут включены в какой-либо сегмент данных... это намеренно?
Ответ 7
Я не эксперт, но разве вы не в четыре раза увеличиваете свои потребности в памяти, копируя список, а затем создавая новый список пар из двух списков? Почему бы просто не сделать следующее:
dtsegs = [(dtg0[i], dtg0[i+1]) for i in range(len(dtg0)-1)]
Не знаю, что такое "Pythonic".
EDIT: На самом деле, глядя на то, что вам нужно сделать с этим списком кортежей, вы можете просто сделать это [i] и [i + 1] материал прямо на этом уровне и даже не создать эту новую структуру вообще. Я не знаю, сколько дат, с которыми вы имеете дело, хотя, если это небольшое число, я полагаю, это не имеет большого значения.
Для чего это стоит, пара других ответчиков здесь, кажется, неправильно понимает ваш вопрос, хотя я не могу комментировать их сообщения, так как у меня пока нет достаточной репутации:) Решение Ignacio Vazquez-Abrams кажется лучшим для меня, хотя его "следующий (dtg0)", вероятно, должен быть следующим (dtg1) "(?)