Python에서 사전 이동
오늘 #100DaysOfCode 챌린지를 다시 시작했습니다(백만 번째). 저는 이 도전에 실제로 성공하기로 결심했고 포기하지 않습니다. 이번에는 Python Bytes Code Challenges website과 그들의 100일 프로젝트 제안을 사용하고 있습니다. 오늘의 도전을 통해 공유하고 싶은 사전 작업에 대한 깔끔한 작은 요령을 배웠습니다.
도전
문제는 dictionary of words 을 통과하는 것입니다. 실제로는
/usr/share/dict/words
의 복사본입니다. 다음 문자 점수를 사용하여 Scrabble에서 가장 높은 점수를 받은 단어를 찾습니다.SCRABBLE_SCORES = [
(1, "E A O I N R T L S U"),
(2, "D G"),
(3, "B C M P"),
(4, "F H V W Y"),
(5, "K"),
(8, "J X"),
(10, "Q Z"),
]
LETTER_SCORES = {
letter: score for score, letters in scrabble_scores
for letter in letters.split()
}
# {"A": 1, "B": 3, "C": 3, "D": 2, ...}
문제
문제는 입력에 유효하지 않은 문자가 있는지 여부에 대해 걱정하고 싶지 않다는 것입니다(적어도 지금은). 따라서 "snoot!43@@@"라는 단어를 검색하면 지금은 SNOOT에 대한 점수를 보고 나머지 문자에 대해 0점을 보고 싶습니다. 이를 수행하는 방법은 여러 가지가 있다는 것을 알고 있지만 내 머릿속에 떠오른 첫 번째 방법은 기본값 0을 사용하는 것이었습니다(즉,
LETTER_SCORES
에 없는 문자를 찾으려고 하면 대신 0을 반환합니다. 제기 KeyError
.)DefaultDict 입력
다행스럽게도 Python은 표준 라이브러리의
defaultdict
모듈 덕분에 우리가 필요로 하는 것과 정확히 일치하는 collections
를 제공합니다. 사용법은 상당히 간단합니다. 입력을 찾을 수 없는 경우 기본값을 구성하는 클래스 또는 함수를 defaultdict
에 제공합니다. 보여드리겠습니다.from collections import defaultdict
zeros = defaultdict(int)
zeros["a"] = 1
zeros["b"] = zeros["definitely not in there"] + 4
print(zeros)
# => defaultdict(<int>, {"a": 1, "b": 4, "definitely not in there": 0})
zeros
dict는 "definitely not in there"
키를 찾을 수 없기 때문에 default-maker 함수인 int
를 호출합니다. 계속해서 Python REPL을 열고 인수 없이 int
함수를 호출해 보십시오.>>> int()
0
인수 없이 호출된
int
함수는 매번 0을 반환합니다.자신만의 default-maker 함수를 만들 수도 있습니다(그리고 클래스도 작동합니다)!
from random import choice
def confusing_default():
possibles = ["1", 1, True, "banana"]
return choice(possibles)
tricky_dict = defaultdict(confusing_default)
tricky_dict["Ryan"]
# => "banana"
tricky_dict["Python"]
# => True
tricky_dict["Why would you do this?"]
# => 1
tricky_dict
# => defaultdict(<confusing_default>, {"Ryan": "banana", "Python": True, "Why would you do this?": 1})
종종
lambdas
를 사용하면 작업을 조금 더 빠르게 수행할 수 있습니다.from random import randint
SCREAMING = defaultdict(lambda: "A")
for i in range(20):
key = randint(0, 3)
SCREAMING[key] += "A"
SCREAMING
# => defaultdict(<function <lambda> at 0x108707f28>, {0: 'AAAAAAAA', 1: 'AAAAAAA', 3: 'AAAAA', 2: 'AAAA'})
사실
defaultdict(lambda: 0)
를 사용하는 것이 defaultdict(int)
를 사용하는 것보다 더 명확하고 혼란이 덜하다고 생각합니다.DefaultDict로 업그레이드
이제 마지막으로 빠른 팁을 받을 준비가 되었습니다. 위에서 나는
defaultdicts
를 평범하고 오래된 파이썬LETTER_SCORES
으로 정의했습니다. 원하는 기본 동작을 빠르게 얻으려면 어떻게 해야 합니까? 한 가지 방법은 두 개의 사전을 병합하는 내장dict
기능을 사용하는 것입니다.FORGIVING_SCORES = defaultdict(lambda: 0)
FORGIVING_SCORES.update(LETTER_SCORES)
FORGIVING_SCORES["Q"]
# => 10
FORGIVING_SCORES["@"]
# => 0
만세!
물론 이것은
dict.update()
defaultdict가 유효하지 않은 요청을 각각 저장하기 때문에 완벽한 솔루션은 아닙니다. 엄청난 수의 유효하지 않은 조회가 예상되지 않는다면 괜찮을 것입니다. 하지만 공간 효율성을 유지하는 것이 걱정된다면 다음과 같이 하는 것이 더 나을 것입니다.score = LETTER_SCORES.get("@") or 0
FORGIVING_SCORES
함수는 get
가 발생하면 None
를 반환하고 KeyError
를 사용하면 조회가 잘못되면 정상적인 기본값을 제공할 수 있습니다. 그리고 모두가 행복합니다!2018년 4월 9일 수정: 지적한 바와 같이 기본 값
or
을 제공하면 훨씬 더 간단하게 이 작업을 수행할 수 있습니다.score = LETTER_SCORES.get("@", 0)
마무리
결과적으로 이 블로그 게시물의 전체 이유는 초기 문제에 대한 가장 간단한 해결책이 아니었습니다. 즉,
get
의 작동 방식과 defaultdict
방법에 대해 조금 더 배우게 되었기를 바랍니다.읽어 주셔서 감사합니다!
dict.update
에 원래 게시됨
Reference
이 문제에 관하여(Python에서 사전 이동), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/rpalo/dict-moves-in-python-5b6i텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)