Python의 list 데이터 유형-예제를 통한 심층 분석2

2023. 12. 31. 11:20python/basic

list 연결 및 반복

  1. 연결, 더하기 연산자(+)를 사용합니다.
  2. 반복, 곱셈 연산자(*)를 사용합니다.

list 연결(+ : 연결 연산자)

In [ ]:
[0, 1, 2, 3] + [4, 5, 6] + [7, 8, 9]
In [ ]:
digits = [0, 1, 2, 3, 4, 5]
id(digits)
In [ ]:
digits = digits + [6, 7, 8, 9]
id(digits)

참고: list는 다른 list과만 연결할 수 있습니다. list를 다른 것과 연결하려고 하면 예외가 발생합니다:

In [ ]:
[0, 1, 2, 3, 4, 5] + (6, 7, 8, 9)
In [ ]:
digits = [0, 1, 2, 3, 4, 5]
digits += [6, 7, 8, 9]
digits

일반 연결 연산자와 달리, 증가된 변형은 새 list를 생성하는 대신 대상 list를 제자리에서 변경합니다.

In [ ]:
digits = [0, 1, 2, 3, 4, 5]
id(digits)
In [ ]:
digits += [6, 7, 8, 9]
id(digits)

list 내용 반복

반복은 주어진 list의 콘텐츠를 특정 횟수만큼 복제하는 것으로 구성됩니다. 두 개의 피연산자를 사용하는 반복 연산자(*)를 사용하여 이를 달성할 수 있습니다.

  1. 반복하고 싶은 내용이 있는 목록
  2. 콘텐츠를 반복해야 하는 횟수
In [ ]:
["A", "B", "C"] * 3
In [ ]:
3 * ["A", "B", "C"]

반복 연산자에는 증강 반복 연산자라고 부르는 증강 변형도 있습니다.

In [ ]:
letters = ["A", "B", "C"]
letters *= 3
letters

목록 반전 및 정렬

값 목록을 뒤집고 특별히 정렬하는 것은 프로그래밍에서 일반적인 작업입니다. Python에는 이러한 작업을 수행하기 위한 reversed() 및 sorted() 함수가 내장되어 있습니다. list 작업을 할 때 대상 list를 제자리에서 역순으로 정렬하는 .reverse() 및 .sort() 메소드도 있습니다.

list 반전: reversed() 및 .reverse()

내장된 reversed() 함수는 시퀀스를 인수로 사용하고 해당 시퀀스의 값을 역순으로 생성하는 반복자를 반환합니다.

In [ ]:
digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

reversed(digits)
In [ ]:
list(reversed(digits))
In [ ]:
digits

reversed() 함수는 입력 개체를 수정하지 않습니다. 일반적으로 데이터를 역순으로 반복하는 방법으로 루프에서 reversed()를 사용합니다. 데이터에 대한 참조를 유지해야 하는 경우 list()를 사용하고 해당 반환 값을 원래 시퀀스와 완전히 독립적인 새 변수에 할당할 수 있습니다.

reversed()은 입력 시퀀스에서 항목을 느리게 검색한다는 점에 유의하는 것이 중요합니다. 즉, 반전 프로세스 중에 입력 순서에 무언가 변경되면 해당 변경 사항이 최종 결과에 반영됩니다.

In [ ]:
numbers = [1, 2, 3]

reversed_numbers = reversed(numbers)
next(reversed_numbers)
In [ ]:
list(reversed_numbers)
In [ ]:
numbers[1] = 222
next(reversed_numbers)
In [ ]:
numbers
In [ ]:
next(reversed_numbers)
In [ ]:
list(reversed_numbers)

reversed() 함수는 원래 list를 변경하지 않고 list를 역순으로 반복하려는 경우에 유용합니다. list가 있는데 어떤 이유로든 해당 내용을 지속적으로 반전시켜야 한다면 어떻게 될까요? 이 경우 .reverse() 방법을 사용할 수 있습니다.

In [ ]:
digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

digits.reverse()
digits

.reverse() 메소드는 list를 제자리에서 뒤집습니다. 즉, 기존 list에서 .reverse()를 호출하면 변경 사항이 기본 list에 반영됩니다.

reversed()이 반복자를 반환하는 반면 .reverse() 메소드는 None을 반환한다는 점에 유의하세요.

In [ ]:
digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

reversed_digits = digits.reverse()
reversed_digits is None

이 예에서 reversed_digits은 반전된 숫자 list를 가져오지 않습니다. 대신 이 기본 list를 변경하고 유익한 반환 값이 없기 때문에 None를 얻습니다.
마지막으로 슬라이싱은 기존 list의 역방향 복사본을 얻는 데 사용할 수 있는 또 다른 기술입니다.

In [ ]:
digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

digits[::-1]

step을 -1와 같은 음수로 설정하면 슬라이싱 연산자에게 오른쪽에서 왼쪽으로 항목을 추출하도록 지시할 수 있습니다.

list 정렬 sorted() 및 .sort()

원래 list를 변경하지 않고 값 list를 정렬해야 하는 경우 내장된 sorted() 기능을 사용할 수 있습니다.

In [ ]:
numbers = [2, 9, 5, 1, 6]

sorted(numbers)
In [ ]:
numbers
In [ ]:
sorted_numbers = sorted(numbers)
sorted_numbers

참고: sorted()는 반복자가 아닌 list를 반환한다는 점에 유의하는 것이 중요합니다. 이 동작은 list 대신 반복자를 반환하는 reversed()과 다릅니다.

In [ ]:
words = ["Hello,", "World!", "I", "am", "a", "Pythonista!"]

sorted(words)

Python의 기본 문자 집합에서는 대문자가 소문자 앞에 오기 때문에 UTF-8의 경우 "Hello"가 첫 번째 위치에 있고 "am"가 마지막 위치에 있습니다.

기본적으로 sorted() 함수는 list 항목을 오름차순으로 정렬합니다. 항목을 내림차순으로 정렬해야 하는 경우 reverse 키워드 전용 인수를 사용할 수 있습니다. 이 인수의 기본값은 False입니다. True로 설정하면 데이터가 내림차순으로 표시됩니다.

In [ ]:
numbers = [2, 9, 5, 1, 6]

sorted(numbers, reverse=True)

데이터 세트의 값 수가 짝수인 경우 중앙값은 중간에 있는 두 값의 평균입니다. 다음은 값 샘플의 중앙값을 계산할 수 있는 Python 함수입니다.

In [ ]:
def median(samples):
    n = len(samples)
    middle_index = n // 2
    sorted_samples = sorted(samples)
    # Odd number of values
    if n % 2:
        return sorted_samples[middle_index]
    # Even number of values
    lower, upper = middle_index - 1, middle_index + 1
    return sum(sorted_samples[lower:upper]) / 2

median([3, 5, 1, 4, 2, 6])

sorted() 함수는 key라는 또 다른 키워드 전용 인수도 허용합니다. 이 인수를 사용하면 각 list 항목에서 비교 키를 추출하는 단일 인수 함수를 지정할 수 있습니다.

사용 방법의 예로 key 직원의 이름, 나이, 직위 및 급여를 포함하여 직원의 데이터가 포함된 각 튜플이 있는 튜플 목록이 있다고 가정해 보겠습니다. 이제 직원을 연령별로 정렬한다고 가정해 보세요.

In [ ]:
employees = [
    ("John", 30, "Designer", 75000),
    ("Jane", 28, "Engineer", 60000),
    ("Bob", 35, "Analyst", 50000),
    ("Mary", 25, "Service", 40000),
    ("Tom", 40, "Director", 90000)
]

sorted(employees, key=lambda employee: employee[1])
In [ ]:
sorted(employees, key=lambda employee: employee[3], reverse=True)

새 정렬된 데이터 list를 가져오는 대신 list를 제자리에서 정렬해야 하는 경우 .sort() 메소드를 사용할 수 있습니다. 이 방법은 sorted() 함수와 유사합니다.

In [ ]:
numbers = [2, 9, 5, 1, 6]

numbers.sort()
numbers

sorted()과 .sort()의 주요 차이점은 전자는 정렬된 데이터의 새 list를 반환하는 반면 후자는 대상 list를 제자리에 정렬한다는 것입니다. 또한 .sort()은 메소드이므로 list 객체에서 호출해야 합니다.

순회 list

for 루프를 사용하여 list 반복

In [ ]:
colors = [
    "red",
    "orange",
    "yellow",
    "green",
    "blue",
    "indigo",
    "violet"
]

for color in colors:
    print(color)

이 예에서는 list를 사용하고 있지만 튜플, 문자열, 집합 또는 기타 반복 가능 항목에서도 동일하게 작동합니다.

In [ ]:
for i, color in enumerate(colors):
    print(f"{i} is the index of '{color}'")

enumerate() 함수는 iterable을 취하고 iterator를 반환합니다. 이 반복자는 요청 시 두 항목으로 구성된 튜플을 생성합니다.

Python은 값 list를 반복할 때 사용할 수 있는 다른 많은 도구를 제공합니다. 예를 들어 reversed()을 사용하여 list를 역순으로 반복할 수 있습니다.

In [ ]:
for color in reversed(colors):
    print(color)

또 다른 일반적인 요구 사항은 정렬된 순서로 list를탐색하는 것입니다.ㅡ

In [ ]:
numbers = [2, 9, 5, 1, 6]

for number in sorted(numbers):
    print(number)

Python 도구 키트를 계속해서 살펴보면 다양한 방법으로 list를 탐색할 수 있는 다른 도구를 많이 찾을 수 있습니다. 예를 들어, 여러 list를 병렬로 반복할 수 있는 zip() 함수가 있습니다.

In [ ]:
integers = [1, 2, 3]
letters = ["a", "b", "c"]
floats = [4.0, 5.0, 6.0]

for i, l, f in zip(integers, letters, floats):
    print(i, l, f)

이 예에서는 zip()을 사용하여 세 개의 list를 병렬로 반복합니다. zip() 함수는 튜플의 반복자를 반환합니다.

숫자 list가 있고 홀수 값만 제거하려고 한다고 가정해 보겠습니다. 이 상황에서는 첫 번째 시도로 다음과 같은 것을 시도해 볼 수 있습니다.

In [ ]:
numbers = [2, 9, 5, 1, 6]

for number in numbers:
    if number % 2:
       numbers.remove(number)

numbers

안타깝게도 9 및 1만 제거되었으며 5은 list에 남아 있습니다. list에서 항목을 제거하면 해당 색인이 이동하여 실행 중인 for 루프 내부의 색인을 방해하기 때문에 이러한 예상치 못한 잘못된 동작이 발생했습니다. 몇 가지 방법으로 이 문제를 피할 수 있습니다.
예를 들어 원본 list의 복사본을 반복할 수 있습니다.

In [ ]:
numbers = [2, 9, 5, 1, 6]

for number in numbers[:]:
   if number % 2:
        numbers.remove(number)

numbers

[:] 연산자를 사용하여 list의 얕은 복사본을 만듭니다. 이 복사본을 사용하면 원본 데이터를 안전한 방식으로 반복할 수 있습니다. 복사본이 있으면 이전과 마찬가지로 for 루프에 입력합니다.

또는 list를 역순으로 반복할 수 있습니다.

In [ ]:
numbers = [2, 9, 5, 1, 6]

for number in reversed(numbers):
    if number % 2:
        numbers.remove(number)

numbers

반복할 때마다 list의 오른쪽 끝에서 마지막 항목만 제거하면 list 길이가 변경되지만 인덱싱은 영향을 받지 않습니다. 이를 통해 인덱스를 해당 list 요소에 올바르게 매핑할 수 있습니다.

Comprehension을 사용하여 새로운 목록 작성

Comprehension은 기본적으로 list 변환 도구입니다. 이를 통해 다른 list이나 반복 가능한 데이터에서 변환된 데이터로 목록을 만들 수 있습니다.

In [ ]:
numbers = ["2", "9", "5", "1", "6"]

numbers = [int(number) for number in numbers]
numbers

Comprehension의 표현식은 문자열에서 정수로의 변환을 실행합니다. 최종 결과는 numbers 변수에 다시 할당하는 새 list의 개체입니다.

이 Comprehension는 enumerate() 함수를 사용하는 루프와 동일합니다.

In [ ]:
numbers = ["2", "9", "5", "1", "6"]

for i, number in enumerate(numbers):
    numbers[i] = int(number)

numbers

또한 comprehensions을 사용하여 기존 list를 필터링할 수도 있습니다. 예를 들어 정수 값 list가 있고 원래 list에서 짝수 값만 포함하는 새 list를 만들고 싶다고 가정해 보겠습니다.

In [ ]:
integers = [20, 31, 52, 6, 17, 8, 42, 55]

even_numbers = [number for number in integers if number % 2 == 0]
even_numbers

기능 도구를 사용하여 목록 처리

또한 map() 및 filter()와 같은 일부 Python 함수형 프로그래밍 도구를 활용하여 값 list를 탐색할 수도 있습니다. 이러한 함수에는 입력 반복 가능 항목을 반복하고 지정된 결과를 반환하는 내부 루프가 있습니다.

예를 들어 map() 함수는 변환 함수와 반복 가능 함수를 인수로 사용합니다. 그런 다음 iterable의 모든 항목에 함수를 적용한 결과 항목을 생성하는 반복자를 반환합니다.

map()을 사용하면 다음 코드를 사용하여 숫자 list를 정수로 변환할 수 있습니다.

In [ ]:
numbers = ["2", "9", "5", "1", "6"]

numbers = list(map(int, numbers))
numbers

이 예에서 map()는 루프의 에 있는 모든 항목에 int() 적용됩니다.

기존 list에서 값을 필터링해야 하는 경우 내장된 filter() 기능을 사용할 수 있습니다. 이 함수는 조건자 함수와 반복 가능한 데이터라는 두 가지 인수를 사용합니다. 그런 다음 조건자 함수가 테스트하는 특정 조건을 충족하는 항목을 생성하는 반복자를 반환합니다.

In [ ]:
integers = [20, 31, 52, 6, 17, 8, 42, 55]

even_numbers = list(filter(lambda number: number % 2 == 0, integers))
even_numbers

list의 다른 기능 탐색

list에서 항목 찾기

Python에는 기존 list에서 값을 검색할 수 있는 몇 가지 도구가 있습니다. 예를 들어, 값이 list에 있는지 여부만 빠르게 확인해야 하지만 값을 가져올 필요는 없다면 list에 대한 멤버십 테스트를 실행하는 연산자 in 혹은 not in 를 사용할 수 있습니다.

item in list_object item not in list_object

In [ ]:
usernames = ["john", "jane", "bob", "david", "eve"]

"linda" in usernames
In [ ]:
"bob" not in usernames

.index() 메소드는 기존 list에서 특정 값을 찾는 데 사용할 수 있는 또 다른 도구입니다. 이 메소드는 지정된 값을 찾기 위해 list를 순회합니다. 값이 list에 있으면 메서드는 해당 인덱스를 반환합니다.

In [ ]:
usernames = ["john", "jane", "bob", "david", "eve"]

usernames.index("eve")
In [ ]:
usernames.index("linda")

검색 대상 값이 list에 여러 번 나타나는 경우 .index()는 첫 번째 항목의 색인을 반환합니다.

In [ ]:
sample = [12, 11, 10, 50, 14, 12, 50]

sample.index(12)

다른 메소드는 .count()이라고 하며, 이를 통해 주어진 값이 list에 몇 번이나 존재하는지 확인할 수 있습니다.

In [ ]:
sample = [12, 11, 10, 50, 14, 12, 50]

sample.count(12)
In [ ]:
sample.count(100)

.count() 메소드는 항목을 인수로 사용하고 입력 항목이 기본 list에 나타나는 횟수를 반환합니다. 항목이 list에 없으면 0 가 표시됩니다

목록의 길이, 최대값, 최소값 얻기

목록의 길이를 확인하려면 내장된 len() 함수를 사용하세요.

In [ ]:
grades = [80, 97, 86, 100, 98, 82]
n = len(grades)
sum(grades) / n

숫자 값 list에 대해 자주 수행하는 또 다른 작업은 최소값과 최대값을 찾는 것입니다.

In [ ]:
min([3, 5, 9, 1, -5])
In [ ]:
max([3, 5, 9, 1, -5])

list 비교

In [ ]:
[2, 3] == [2, 3]
In [ ]:
[5, 6] != [5, 6]
In [ ]:
[5, 6, 7] < [7, 5, 6]
In [ ]:
[5, 6, 7] > [7, 5, 6]
In [ ]:
[4, 3, 2] <= [4, 3, 2]
In [ ]:
[4, 3, 2] >= [4, 3, 2]

두 list를 비교할 때 Python은 사전순 정렬을 사용합니다. 각 list의 처음 두 항목을 비교합니다. 서로 다른 경우 이 차이에 따라 비교 결과가 결정됩니다. 동일하면 Python은 두 항목 중 하나가 소진될 때까지 다음 두 항목을 비교하는 식으로 계속됩니다.

다양한 길이의 list를 비교할 수도 있습니다.

In [ ]:
[5, 6, 7] < [8]
In [ ]:
[5, 6, 7] == [5]

첫 번째 표현식에서는 전자가 후자 보다 작기 때문에 True 결과를 ​​얻습니다. 두 번째 예에서는 False 를 얻습니다. list의 길이가 동일하지 않아 동일할 수 없기 때문에 이 결과는 타당합니다.

Python 목록의 일반적인 문제

  • 사본과 목록의 별칭 혼동: 한 별칭을 변경하면 다른 별칭에 영향을 주기 때문에 문제가 발생할 수 있습니다. 이 문제의 실제 예를 보려면 list의 별칭 섹션을 살펴보세요.
  • 대부분의 list 메소드는 list를 변경하고 새 list 대신 None 반환한다는 사실을 잊어버립니다. 새로운 list가 있다고 생각하여 list 메소드의 반환 값을 변수에 할당할 때 일반적으로 문제가 발생하지만 실제로는 None를 얻습니다. 이 문제의 실제 예를 보려면 list 역순 및 정렬 섹션을 확인하세요.
  • .append()와 .extend() 혼동 : .append()이 list 끝에 단일 항목을 추가하기 때문에 문제가 발생할 수 있습니다. .extend() 메소드는 여러 항목의 압축을 풀고 추가합니다. 이러한 방법의 작동 방식에 대한 자세한 내용은 동적으로 list 확장 및 축소 섹션을 살펴보세요.
  • 함수 정의에서 빈 list를 기본 인수 값으로 사용: Python이 함수를 처음 구문 분석할 때 기본 인수 값이 정의되기 때문에 예기치 않은 동작이 발생할 수 있습니다.
In [ ]:
def append_to(item, target=[]):
    target.append(item)
    return target
In [ ]:
append_to(1)
In [ ]:
append_to(2)
In [ ]:
append_to(1)

이 문제를 방지하려면 None을 기본값으로 사용하세요.

In [ ]:
def append_to(item, target=None):
    if target is None:
        target = []
    target.append(item)
    return target

append_to(1)
In [ ]:
append_to(2)
In [ ]:
append_to(1)

내장 클래스 하위 클래스화 list 클래스

경우에 따라 list의 기능을 확장하거나 일부 표준 동작을 사용자 정의하는 목록형 클래스를 만들어야 할 수도 있습니다. 오랫동안 C에 구현된 내장 Python 유형에서 직접 상속하는 것이 불가능했습니다. Python 2.2에서는 이 문제가 해결되었습니다. 이제 list를 포함하여 내장 유형을 하위 클래스할 수 있습니다.

In [ ]:
class GradeList(list):
    def average(self):
        return sum(self) / len(self)

grades = GradeList([80, 97, 86, 100, 98])
grades.append(82)
grades.average()
In [ ]:
grades[0] = 95
grades.average()

이 코드 스니펫에서는 list 에서 직접 상속합니다. 반복 가능한 성적 값을 사용하여 GradeList를 인스턴스화할 수 있습니다. 클래스는 일반 목록으로 작동합니다. .append() 및 .extend() 와 같은 list 메소드를 사용하여 인덱싱 및 슬라이싱 등을 수행할 수 있습니다.

예를 들어, GradeList 클래스를 계속 개선하고 싶고 일부 입력 유효성 검사 기능을 추가하려고 한다고 가정해 보겠습니다. 수업에서 모든 입력 성적을 검증하여 1 및 100 사이의 숫자인지 확인하기를 원합니다.

이 상황에서는 list의 표준 기능을 크게 변경해야 합니다. list에 새 항목을 추가하는 모든 메소드를 수정해야 합니다. 이러한 방법에는 다음과 같은 특수 방법이 포함됩니다.

  • .init(), 모든 클래스의 새 인스턴스를 초기화합니다.
  • .setitem(), 인덱싱 작업을 지원합니다.

또한 .append(), .extend() 및 .insert() 메소드를 맞춤설정해야 합니다. 또한 연결을 실행할 때 클래스에서 입력의 유효성을 검사하도록 하려면 .add(), .radd() 및 iadd() 를 포함한 다른 특수 메서드를 업데이트해야 합니다.

다음은 가능하지만 최소한의 GradeList 수업 업데이트입니다.

In [ ]:
# grades.py

class GradeList(list):
    def __init__(self, grades):
        grades = [self._validate(grade) for grade in grades]
        super().__init__(grades)

    def __setitem__(self, index, grade):
        if isinstance(index, slice):
            start, stop, step = index.indices(len(self))
            grades = [self._validate(grade) for grade in grade]
            return super().__setitem__(slice(start, stop, step), grades)
        super().__setitem__(index, self._validate(grade))

    def __add__(self, grades):
        grades = [self._validate(grade) for grade in grades]
        grades = super().__add__(grades)
        return self.__class__(grades)

    __radd__ = __add__

    def __iadd__(self, grades):
        grades = [self._validate(grade) for grade in grades]
        return super().__iadd__(grades)

    def append(self, grade):
        return super().append(self._validate(grade))

    def extend(self, grades):
        grades = [self._validate(grade) for grade in grades]
        return super().extend(grades)

    def average(self):
        return sum(self) / len(self)

    def _validate(self, value):
        if not isinstance(value, (int, float)):
            raise TypeError("grades must be numeric")
        if not (0 <= value <= 100):
            raise ValueError("grade must be between 0 and 100")
        return value

이 클래스는 일반 list에 항목을 추가하는 모든 표준 메소드를 확장합니다. 이러한 모든 방법은 입력 성적이 유효한지 확인하기 위해 ._validate() 도우미 방법을 사용합니다. 이 메서드는 값이 숫자인지 확인합니다. 또한 0 및 100 사이에 있는지 확인합니다.

위 코드에서 결론을 내릴 수 있듯이 하위 클래스에 있는 list의 표준 동작을 수정하려면 많은 작업이 필요하며 오류가 발생하기 쉽습니다.

In [ ]:
from grades import GradeList

grades = GradeList([80, 97, 86, 200])
In [ ]:
grades = GradeList([80, 97, 86, 100])
grades.average()
In [ ]:
grades[0] = 955
In [ ]:
grades[0] = 95
grades
In [ ]:
grades.append(-98)
In [ ]:
grades.append(98)
grades
In [ ]:
grades += [88, 100]
grades
In [ ]:
grades[:3] = [100, 100, 100]
grades
In [ ]:
grades.average()

list를 실행에 옮기기

list에서 반복 항목 제거

set 객체를 사용하는 것은 세트가 반복 항목을 허용하지 않기 때문에 그 중 하나일 수 있습니다.

In [ ]:
list(set([2, 4, 5, 2, 3, 5]))

이 솔루션은 새로운 고유 값 목록을 얻기 때문에 효과적입니다. 그러나 Python 세트는 포함된 항목을 반드시 순서대로 유지하지는 않습니다. 따라서 원래 삽입 순서를 유지하는 다른 기술을 사용할 수도 있습니다.
list에서 반복되는 항목을 제거하는 문제를 해결하는 가장 안전한 방법은 원래 list에서 고유한 값을 가진 새 list를 만드는 것입니다.

In [ ]:
def get_unique_items(list_object):
    result = []
    for item in list_object:
        if item not in result:
            result.append(item)
    return result

get_unique_items([2, 4, 5, 2, 3, 5])

이 함수에서는 list를 인수로 받아들입니다. 그런 다음 함수 결과를 저장할 새 빈 list를 정의합니다. 루프에서는 입력 list의 항목을 반복합니다. 조건부는 result에 현재 항목이 없는지 확인합니다. 그렇다면 .append()를 사용하여 항목을 추가하세요. 루프가 끝나면 고유한 값이 포함된 결과 list가 반환됩니다.

In [ ]:
def get_unique_items(list_object):
    result = []
    unique_items = set()
    for item in list_object:
        if item not in unique_items:
            result.append(item)
            unique_items.add(item)
    return result

len(get_unique_items(range(100_000)))

세트를 사용하면 주어진 값이 이미 존재하는지 빠르게 확인할 수 있습니다. 세트는 in 및 not in 연산자를 다르게 구현하여 list 대응 항목보다 훨씬 빠르게 만듭니다. 이 함수는 즉시 반환되지만 이제 모든 값을 두 곳에 저장하므로 두 배의 메모리가 필요합니다.

다차원 list 만들기

다차원 목록을 만드는 빠르고 안전한 방법은 for 루프나 comprehensions을 사용하는 것입니다. 예를 들어, 숫자 값으로 구성된 5x5 행렬을 만들고 모든 값을 0로 초기화한다고 가정해 보겠습니다.

In [ ]:
matrix = []

for row in range(5):
    matrix.append([])
    for _ in range(5):
        matrix[row].append(0)

matrix

다음과 같은 list comprehension를 사용하면 위의 예와 동일한 결과를 얻을 수 있습니다.

In [ ]:
[[0 for _ in range(5)] for _ in range(5)]
In [ ]:
[[0] * 5 for _ in range(5)]
In [ ]:
[[0] * 5 for _ in range(5)]

이 결과 매트릭스는 내부적으로 이전의 모든 솔루션과 상당히 다르게 작동합니다. 특정 행에서 하나의 값을 변경하면 변경 사항이 다른 모든 행에 반영됩니다.

In [ ]:
matrix = [[0] * 5] * 5
matrix
In [ ]:
matrix[0][0] = 1
matrix

list를 반복 연산자에 인수로 전달하면 복사본 대신 list의 별칭을 얻습니다. 따라서 행렬의 모든 행은 실제로 동일한 list입니다.

다차원 list 평면화

In [ ]:
matrix = [[0, 1, 2], [10, 11, 12], [20, 21, 22]]

flattened_list = []
for row in matrix:
    flattened_list.extend(row)

flattened_list

list를 덩어리로 나누기

In [ ]:
def split_list(list_object, chunk_size):
    chunks = []
    for start in range(0, len(list_object), chunk_size):
        stop = start + chunk_size
        chunks.append(list_object[start:stop])
    return chunks

split_list([1, 2, 3, 4, 5, 6, 7, 8, 9], 4) # 4는 chunk 범위의 수

list를 스택 또는 대기열로 사용

예를 들어, 스택이나 LIFO(후입선출) 데이터 구조를 모방하려면 .append() 항목을 스택의 맨 위로 밀어 넣습니다. 마찬가지로 인수 없이 .pop()를 사용하여 스택 상단에서 항목을 가져올 수 있습니다.

In [ ]:
stack = []

stack.append("Copy")
stack.append("Paste")
stack.append("Remove") # 스택의 맨 "위", 즉 스택의 상단임

stack
In [ ]:
stack.pop()
In [ ]:
stack.pop()

또는 대기열이나 선입선출(FIFO) 데이터 구조를 에뮬레이션하려는 경우 .append()을 사용하여 list 끝에 항목을 배치할 수 있습니다. 이를 큐에 넣기 작업이라고 합니다. 마찬가지로 .pop()와 0을 인수로 사용하여 대기열의 왼쪽 끝에서 항목을 반환하고 제거할 수 있습니다.

In [ ]:
queue = []

queue.append("John")
queue.append("Jane")
queue.append("Linda")

queue
In [ ]:
queue.pop(0)
In [ ]:
queue.pop(0)

list 사용 여부 결정

일반적으로 다음이 필요할 때 목록을 사용해야 합니다.

  • 데이터 순서 유지: list는 항목 삽입 순서를 유지합니다.
  • 값의 순서 저장: list는 관련된 값의 순서를 저장해야 할 때 좋은 선택입니다.
  • 데이터 변형: list는 여러 변형을 지원하는 변경 가능한 데이터 유형입니다.
  • 색인을 기준으로 임의 값에 액세스: list는를 사용하면 색인을 기반으로 요소에 빠르고 쉽게 액세스할 수 있습니다.

반대로 다음과 같은 경우에는 목록을 사용하지 마세요.

  • 불변 데이터 저장: 이 경우 튜플을 사용해야 합니다. 변경이 불가능하고 메모리 효율성이 더 높습니다.
  • 데이터베이스 레코드 표시: 이 경우 튜플이나 데이터 클래스 사용을 고려하세요.
  • 고유하고 순서가 지정되지 않은 값 저장: 이 시나리오에서는 집합이나 사전 사용을 고려하세요. 세트는 중복된 값을 허용하지 않으며 사전은 중복된 키를 보유할 수 없습니다.
  • 항목이 중요하지 않은 여러 멤버십 테스트 실행: 이 경우 set 사용을 고려해 보세요. 세트는 이러한 유형의 작업에 최적화되어 있습니다.
  • 고급 배열 및 행렬 연산 실행: 이러한 상황에서는 NumPy의 특수 데이터 구조 사용을 고려해 보세요.
  • 데이터를 스택이나 대기열로 조작: 이 경우 collections 모듈 또는 Queue, LifoQueue 또는PriorityQueue 로 부터 deque 사용을 고려하세요. 이러한 데이터 유형은 스레드로부터 안전하며 양쪽 끝에서 빠르게 삽입하고 제거하는 데 최적화되어 있습니다.