2011-09-04 2 views
3

Я этот список кортежей:Python: Каков правильный способ изменения элементов списка?

l = [('a','b'),('c','d'),('e','f')] 

И два параметра: ключевое значение, и новое значение для изменения. Например,

key = 'a' 
new_value= 'B' # it means, modify with 'B' the value in tuples where there's an 'a' 

Я это два варианта (оба произведения):

f = lambda t,k,v: t[0] == k and (k,v) or t 
new_list = [f(t,key,new_value) for t in l] 
print new_list 

и

new_list = [] 
for i in range(len(l)): 
    elem = l.pop() 
    if elem[0] == key: 
     new_list.append((key,new_value)) 
    else: 
     new_list.append(elem) 
print new_list 

Но, я новичок в Python, и не знаю, если его право.

Вы можете мне помочь? Спасибо!

+5

Если вы хотите использовать словарные функции, используйте [словарь] (http://docs.python.org/tutorial/datastructures.html#dictionaries) , Очевидно, это означает, что ключи должны быть уникальными; Я не знаю, если это противоречит вашим требованиям. – NullUserException

+0

Спасибо, я знаю словарь. Это более общий вопрос, как изменить элементы в списке. – santiagobasulto

+0

Это не изменяет. List, он создает новую копию. Какой ты хочешь? –

ответ

2

Чтобы изменить существующий список, просто используйте назначение списка, например.

>>> l = [('a','b'),('c','d'),('e','f')] 
>>> l[0] = ('a','B') 
>>> print l 
[('a', 'B'), ('c', 'd'), ('e', 'f')] 

Обычно я предпочитаю создавать новый список, используя понимание, например.

[(key, new_value) if x[0] == key else x for x in l] 

Но, как первый комментарий уже упоминалось, это звучит, как вы пытаетесь сделать список делать то, что вы действительно должны быть с помощью Dict для вместо.

+0

Oo Вы уверены, что не означает 'l [0] = ('a', 'B')'? – Tadeck

+0

o_O действительно .. по какой-то глупой причине я думал о сплюснутом списке, но я все-таки писал кортежи. Благодарю. – wim

+0

Действительно простое решение. Благодаря! – santiagobasulto

3

Чтобы создать новый список, список понимание будет делать:

In [102]: [(key,'B' if key=='a' else val) for key,val in l] 
Out[102]: [('a', 'B'), ('c', 'd'), ('e', 'f')] 

Чтобы изменить список на месте:

l = [('a','b'),('c','d'),('e','f')] 

for i,elt in enumerate(l): 
    key,val=elt 
    if key=='a': 
     l[i]=(key,'B') 
print(l)    
# [('a', 'B'), ('c', 'd'), ('e', 'f')] 
+0

Ничего себе, не знал этих «inline ifs» и не перечислял функцию. Благодаря! – santiagobasulto

+0

@santiagobasulto: рад, что я мог бы помочь. «Inline ifs» называются [условными выражениями] (http://docs.python.org/reference/expressions.html#conditional-expressions) или тройными выражениями в Python. – unutbu

2

Вот подход, который я хотел бы использовать.

>>> l = [('a','b'),('c','d'),('e','f')] 
>>> key = 'a' 
>>> new_value= 'B' 
>>> for pos in (index for index, (k, v) in enumerate(l) if k == key): 
...  l[pos] = (key, new_value) 
...  break 
... else: 
...  l.append((key, new_value)) 
... 
>>> l 
[('a', 'B'), ('c', 'd'), ('e', 'f')] 

Это выглядит очень много, как OrderedDict, хотя; пары ключ-значение с сохраненным порядком. Вы можете захотеть взглянуть на это и увидеть, если она соответствует вашим потребностям

Edit: Заменено try: ... except StopIteration: с for: ... break ... else: поскольку это может выглядеть немного менее странно.

+0

Вы занимаетесь сложным решением! –

+0

Я не считаю это сложным. 'list.index' недоступен, потому что мы ищем элемент, который * каким-то образом похож * на ключ, а не равен ключу. 'enumerate' довольно нормальный, и я не знаю альтернативного идиома, чтобы получить * первый элемент * от генератора, кроме' . next() 'и catching исключение, если оно не найдено. Другие альтернативы были бы либо бесполезно многословными, либо генерировали промежуточные списки. – SingleNegationElimination

+0

Я бы назвал это сложным в том смысле, что Zen of Python говорит о сложном, чем сложном. Когда есть простое решение - итерация с полным циклом 'for', а не с использованием' .next() 'и необходимость иметь дело с ловушкой' StopIteration' - это часто бывает лучше. Я должен был кратко подумать о том, что ваше решение делает, чтобы проверить его правильность, тогда как я могу посмотреть на мое решение или на другие подобные, которые были опубликованы, и понять, что делается немедленно. Мне кажется, что ошибка в стиле 'for-if' была бы намного более очевидной. –

4

Вот одно из решений, связанных с изменением позиций на месте.

def replace(list_, key, new_value): 
    for i, (current_key, current_value) in enumerate(list_): 
     if current_key == key: 
      list_[i] = (key, new_value) 

Или, чтобы добавить, если это не там,

def replace_or_append(list_, key, new_value): 
    for i, (current_key, current_value) in enumerate(list_): 
     if current_key == key: 
      list_[i] = (key, new_value) 
      break 
    else: 
     list_.append((key, new_value)) 

Использование:

>>> my_list = [('a', 'b'), ('c', 'd')] 
>>> replace(my_list, 'a', 'B') 
>>> my_list 
[('a', 'B'), ('c', 'd')] 

Если вы хотите создать новый список, список понимание легче.

>>> my_list = [('a', 'b'), ('c', 'd')] 
>>> find_key = 'a' 
>>> new_value = 'B' 
>>> new_list = [(key, new_value if key == find_key else value) for key, value in my_list] 
>>> new_list 
[('a', 'B'), ('c', 'd')] 

И если вы хотите, чтобы это добавить, если его там не было,

>>> if len(new_list) == len(my_list): 
...  new_list.append((find_key, new_value)) 

(Обратите внимание также я изменил свое имя переменного из l, l слишком легко спутать с I и 1 и это лучше всего избегать. Таким образом, мы говорим о PEP8, и я согласен с ним.)

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