for 루프 중에 목록 항목을 수정하는 방법은 무엇입니까?


178

이제 반복 반복 중에 목록을 수정하는 것이 안전하지 않다는 것을 알고 있습니다. 그러나 문자열 목록이 있고 문자열 자체를 제거하고 싶다고 가정하십시오. 변경 가능한 값의 대체는 수정으로 간주됩니까?


20
문자열은 변경 가능한 값이 아닙니다.
user470379

4
@ user470379 : 목록의 요소가 변경 가능한지 여부는 반복하는 동안 목록을 수정하는 것이 안전한지 여부와 관련이 없습니다.
martineau

답변:


144

나쁜 형태로 간주됩니다. 목록에 대한 기존 참조를 유지해야하는 경우 슬라이스 할당과 함께 목록 이해를 대신 사용하십시오.

a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)

10
슬라이스 할당은 영리하며 루프 중에 원본을 수정하지 않지만 원본 길이의 임시 목록을 작성해야합니다.
martineau

11
왜 우리는 b = a를 할당합니까?
Vigrond

9
@Vigrond : print b명령문이 실행될 때 a대체되지 않고 제자리에서 수정 되었는지 알 수 있습니다 . 또 다른 가능성은 print b is a둘 다 여전히 동일한 객체를 참조하는지 확인하는 것입니다.
martineau

12
왜 a [:] =뿐만 아니라 a =?
kdubs

10
@kdubs : "... 목록에 대한 기존 참조를 유지해야하는 경우 슬라이스 할당으로"
Ignacio Vazquez-Abrams

163

아래 루프는 이미 본 요소 만 수정하므로 허용 가능한 것으로 간주됩니다.

a = ['a',' b', 'c ', ' d ']

for i, s in enumerate(a):
    a[i] = s.strip()

print(a) # -> ['a', 'b', 'c', 'd']

다음과는 다릅니다.

a[:] = [s.strip() for s in a]

더 많은 인덱싱 작업이 필요하지만 임시 목록을 만들고 원본을 대체하기 위해 할당 할 필요가 없습니다.

주의 : 이 방법으로 항목 을 수정할 수 있지만 list문제가 발생할 가능성이없는 한 항목 수를 변경할 수 없습니다 .

다음은 내가 의미하는 바의 예입니다. 항목을 삭제하면 해당 시점부터 인덱싱이 엉망이됩니다.

b = ['a', ' b', 'c ', ' d ']

for i, s in enumerate(b):
    if s.strip() != b[i]:  # leading or trailing whitespace?
        del b[i]

print(b)  # -> ['a', 'c ']  # WRONG!

(필수 항목을 모두 삭제하지 않았기 때문에 결과가 잘못되었습니다.)

최신 정보

이것은 매우 인기있는 답변이므로 다음과 같이 "제자리에서"항목을 효과적으로 삭제하는 방법은 다음과 같습니다 (정확한 질문은 아니지만).

b = ['a',' b', 'c ', ' d ']

b[:] = [entry for entry in b if entry.strip() == entry]

print(b)  # -> ['a']  # CORRECT

3
왜 파이썬은 구문에서 개별 요소의 사본 만 만드는가 for i in a? 이것은 매우 반 직관적이며 다른 언어와 다르게 보이고 내 코드에서 오랫동안 디버깅 해야하는 오류가 발생했습니다. 파이썬 튜토리얼에서는 언급조차하지 않습니다. 거기에 어떤 이유가 있어야하지만?
xji

1
@JIXiang : 사본을 만들지 않습니다. 루프 변수 이름을 반복되는 요소 또는 반복되는 항목의 값에 지정합니다.
martineau

1
왜 안될 때 같은 줄에 같은 객체에 두 개의 이름 ( a[i]s)을 사용합니까? 나는 오히려 오히려 할 a[i] = a[i].strip()것이다.
Navin

3
@Navin : a[i] = s.strip()하나의 인덱싱 작업 만 수행 하기 때문입니다.
martineau

1
@martineau enumerate(b)는 모든 반복에서 인덱싱 작업을 수행하고으로 다른 작업을 수행 a[i] =합니다. AFAIK 그것은 루프 반복 당 하나의 인덱싱 작업으로 파이썬 에서이 루프를 구현하는 것은 불가능합니다 :(
Navin

18

for 루프 변형이 하나 더 있는데 enumerate ()를 사용하는 것보다 깨끗해 보입니다.

for idx in range(len(list)):
    list[idx]=... # set a new value
    # some other code which doesn't let you use a list comprehension

19
많은 사람들 range(len(list))이 파이썬에서 코드 냄새 와 같은 것을 사용하는 것을 고려 합니다.
martineau

2
@Reishin : enumerate생성기이므로 튜플 목록을 만들지 않으므로 목록을 반복 할 때 한 번에 하나씩 생성합니다. 어느 것이 더 느린지를 알 수있는 유일한 방법은 timeit입니다.
martineau

3
@martineau 코드 는 예쁘지 않을 수도 있지만, timeit enumerate느리다
Reishin

2
@Reishin : 벤치 마크 코드는 주어진 인덱스에서 목록의 값을 검색 할 필요성을 고려하지 않기 때문에 완전히 유효하지 않습니다.이 답변에도 표시되지 않습니다.
martineau

4
@Reishin : 그런 이유로 귀하의 비교는 정확하게 유효하지 않습니다. 루핑 오버 헤드를 격리하여 측정하고 있습니다. 결론적으로 전체 루프를 실행하는 데 걸리는 시간을 결정하려면 특정 방식으로 루프 루프 내부의 코드에 제공되는 이점으로 인해 오버 헤드 차이가 완화 될 수 있기 때문에 오버 헤드 차이를 측정해야합니다. 그렇지 않으면 사과를 비교하지 않습니다. 사과.
martineau

11

추가 / 제거 요소를 목록으로 변경하지 않는 한 목록을 반복하는 동안 각 요소를 수정하는 것이 좋습니다.

당신은 목록 이해를 사용할 수 있습니다 :

l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]

또는 C-stylefor 루프를 수행하십시오 .

for index, item in enumerate(l):
    l[index] = item.strip()

4

문자열을 그런 식으로 변경할 수 있다면 목록의 "내용"을 변경하지 않습니다. 그러나 파이썬에서는 변경이 불가능합니다. 모든 문자열 작업은 새 문자열을 반환합니다.

변경 가능한 것으로 알고있는 객체 목록이있는 경우 목록의 실제 내용을 변경하지 않는 한이 작업을 수행 할 수 있습니다.

따라서 어떤 종류의지도를 작성해야합니다. 생성기 표현식을 사용하면 반복 할 때 [작업]이 수행되고 메모리가 절약됩니다.


4

다음과 같이 할 수 있습니다 :

a = [1,2,3,4,5]
b = [i**2 for i in a]

리스트 내에서 더 쉽게 반복 할 수 있도록리스트 이해력이라고합니다.


3

Jemshit Iskenderov와 Ignacio Vazquez-Abrams의 답변은 정말 좋습니다. 이 예제를 통해 더 자세히 설명 할 수 있습니다.

a) 두 개의 벡터가있는 목록이 제공됩니다.

b) 목록을 탐색하고 각 배열의 순서를 바꾸고 싶습니다.

당신이 있다고 가정 해 봅시다

v = np.array([1, 2,3,4])
b = np.array([3,4,6])

for i in [v, b]:
    i = i[::-1]   # this command does not reverse the string

print([v,b])

당신은 얻을 것이다

[array([1, 2, 3, 4]), array([3, 4, 6])]

반면에, 당신이 할 경우

v = np.array([1, 2,3,4])
b = np.array([3,4,6])

for i in [v, b]:
   i[:] = i[::-1]   # this command reverses the string

print([v,b])

결과는

[array([4, 3, 2, 1]), array([6, 4, 3])]

1

제거 할 문자열을 결정하기위한 기준이 무엇인지 확실하지 않지만 제거 할 문자열 목록이 있거나 제거 할 수있는 경우 다음을 수행 할 수 있습니다.

my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
    for i in range(my_strings.count(undesirable_string)):
        my_strings.remove(undesirable_string)

my_strings를 [ 'a', 'c', 'e']로 바꿉니다.


0

즉, 동일한 목록을 반복하면서 목록을 수정합니다.

list[:] = ["Modify the list" for each_element in list "Condition Check"]

예:

list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.