Могу ли я рассчитывать на сохранение порядка в кортеже Python? - PullRequest
23 голосов
/ 01 декабря 2010

У меня есть список дат, из которых я хочу построить временные сегменты. Другими словами, превратите [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)

Вопросы ...

  1. Могу ли я рассчитывать на tn-1
  2. Полезно ли копировать исходный список mdtimes со списком? Если нет, то как это сделать?
  3. Цель создания этих кортежей состоит в том, чтобы перебрать их и сегментировать набор данных с tn-1 и tn. Это разумный подход? т.е.

    datasegment = [x for x in bigdata if ( (x['datetime'] > tleft) and (x['datetime'] < tright))] 
    

Спасибо

Ответы [ 7 ]

18 голосов
/ 01 декабря 2010

Заказывается list и tuple.

dtg0, dtg1 = itertools.tee(mdtimes)
next(dtg0)
dtsegs = zip(dtg0, dtg1)
16 голосов
/ 01 декабря 2010
  1. Порядок кортежей такой, как вы вводите значения в кортеж. Они не будут отсортированы, как я думаю, вы спрашиваете. zip снова сохранит порядок, в котором вы вводили значения.

  2. Это приемлемый метод, но у меня есть 2 альтернативных предложения: используйте модуль copy или dtg1 = mdtimes[:].

  3. Звучит разумно.

5 голосов
/ 01 декабря 2010

Вы можете достичь того же с zip:

>>> l = ["t0", "t1", "t2", "t3", "t4", "t5", "t6"]
>>> zip(l[::2], l[1::2])
[('t0', 't1'), ('t2', 't3'), ('t4', 't5')]
3 голосов
/ 01 декабря 2010

Вместо: dtg0 = [x for x in mdtimes], dtg0 = mdtimes[:] подойдет, поскольку вы просто копируете один список в другой.Примечание: начиная с Python 3.3, вы можете просто сказать newlist = oldlist.copy()

Что касается порядка, порядок zip четко определен, и списки, и кортежи являются упорядоченными коллекциями, поэтому у вас не должно возникнуть никаких проблем..

2 голосов
/ 01 декабря 2010

Это ответ на вопрос «Это разумный подход?» (который, похоже, был проигнорирован всеми).

Резюме: Возможно, вам захочется / нужно поднять свой взгляд от превращения парной штуковины из mdtimes в охватывающую проблему (сегментирование bigdata).

Detail:

Желаемое использование результата выражается как:

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, которые имеют временную метку = max (mdtimes), не будут включены ни в один сегмент данных ... это намеренно?

2 голосов
/ 01 декабря 2010

Превращение (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): 
    ....
1 голос
/ 01 декабря 2010

Я не эксперт, но разве вы не увеличиваете свои требования к памяти в четыре раза, копируя список, а затем создавая новый список пар, взятых из двух списков? Почему бы просто не сделать следующее:

dtsegs = [(dtg0[i], dtg0[i+1]) for i in range(len(dtg0)-1)]

Не знаю, как это "Pythonic", хотя.

РЕДАКТИРОВАТЬ: На самом деле, глядя на то, что вам нужно сделать с этим списком кортежей, вы можете просто делать эти [i] и [i + 1] вещи прямо на этом уровне и даже не создавать эту новую структуру вообще. Я не знаю, сколько дат вы имеете дело, хотя - если это небольшое число, я полагаю, это не имеет значения.

Для чего бы то ни было, пара других ответчиков здесь, похоже, неправильно поняли ваш вопрос, хотя я не могу комментировать их посты, так как у меня пока недостаточно репутации :) Решение Игнасио Васкеса-Абрамса кажется лучшим для меня, хотя его "next (dtg0)", вероятно, должно быть "next (dtg1)" (?)

...