파이썬 그룹 기준
인덱스 0이 값이고 인덱스 1이 유형인 데이터 쌍 집합이 있다고 가정합니다.
input = [
('11013331', 'KAT'),
('9085267', 'NOT'),
('5238761', 'ETH'),
('5349618', 'ETH'),
('11788544', 'NOT'),
('962142', 'ETH'),
('7795297', 'ETH'),
('7341464', 'ETH'),
('9843236', 'KAT'),
('5594916', 'ETH'),
('1550003', 'ETH')
]
다음과 같이 유형(첫 번째 인덱스 문자열 기준)으로 그룹화합니다.
result = [
{
'type': 'KAT',
'items': ['11013331', '9843236']
},
{
'type': 'NOT',
'items': ['9085267', '11788544']
},
{
'type': 'ETH',
'items': ['5238761', '962142', '7795297', '7341464', '5594916', '1550003']
}
]
효율적인 방법으로 이를 달성하려면 어떻게 해야 합니까?
2단계로 진행합니다.먼저 사전을 만듭니다.
>>> input = [('11013331', 'KAT'), ('9085267', 'NOT'), ('5238761', 'ETH'), ('5349618', 'ETH'), ('11788544', 'NOT'), ('962142', 'ETH'), ('7795297', 'ETH'), ('7341464', 'ETH'), ('9843236', 'KAT'), ('5594916', 'ETH'), ('1550003', 'ETH')]
>>> from collections import defaultdict
>>> res = defaultdict(list)
>>> for v, k in input: res[k].append(v)
...
그런 다음 해당 사전을 필요한 형식으로 변환합니다.
>>> [{'type':k, 'items':v} for k,v in res.items()]
[{'items': ['9085267', '11788544'], 'type': 'NOT'}, {'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'items': ['11013331', '9843236'], 'type': 'KAT'}]
itertools.groupby로도 가능하지만 입력을 먼저 정렬해야 합니다.
>>> sorted_input = sorted(input, key=itemgetter(1))
>>> groups = groupby(sorted_input, key=itemgetter(1))
>>> [{'type':k, 'items':[x[0] for x in v]} for k, v in groups]
[{'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'items': ['11013331', '9843236'], 'type': 'KAT'}, {'items': ['9085267', '11788544'], 'type': 'NOT'}]
이 두 가지 모두 키의 원래 순서를 따르지 않습니다.질서를 유지하려면 질서 있는 칙령이 필요합니다.
>>> from collections import OrderedDict
>>> res = OrderedDict()
>>> for v, k in input:
... if k in res: res[k].append(v)
... else: res[k] = [v]
...
>>> [{'type':k, 'items':v} for k,v in res.items()]
[{'items': ['11013331', '9843236'], 'type': 'KAT'}, {'items': ['9085267', '11788544'], 'type': 'NOT'}, {'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}]
의 내장 Pythonitertools
모듈에는 실제로 기능이 있지만, 이를 위해서는 먼저 그룹화할 요소가 목록에서 인접하도록 정렬되어야 합니다.
from operator import itemgetter
sortkeyfn = itemgetter(1)
input = [('11013331', 'KAT'), ('9085267', 'NOT'), ('5238761', 'ETH'),
('5349618', 'ETH'), ('11788544', 'NOT'), ('962142', 'ETH'), ('7795297', 'ETH'),
('7341464', 'ETH'), ('9843236', 'KAT'), ('5594916', 'ETH'), ('1550003', 'ETH')]
input.sort(key=sortkeyfn)
이제 입력은 다음과 같습니다.
[('5238761', 'ETH'), ('5349618', 'ETH'), ('962142', 'ETH'), ('7795297', 'ETH'),
('7341464', 'ETH'), ('5594916', 'ETH'), ('1550003', 'ETH'), ('11013331', 'KAT'),
('9843236', 'KAT'), ('9085267', 'NOT'), ('11788544', 'NOT')]
groupby
형식의 2-튜플 시퀀스를 반환합니다.(key, values_iterator)
우리가 원하는 것은 이것을 dict 목록으로 바꾸는 것입니다. 여기서 'type'은 키이고 'items'는 values_iterator에 의해 반환되는 튜플의 0번째 요소 목록입니다.다음과 같이:
from itertools import groupby
result = []
for key,valuesiter in groupby(input, key=sortkeyfn):
result.append(dict(type=key, items=list(v[0] for v in valuesiter)))
지금이다result
질문에 명시된 대로 원하는 받아쓰기가 포함되어 있습니다.
그러나 유형별로 키를 지정하고 각 값에 값 목록을 포함하는 하나의 딕트를 만드는 것을 고려할 수 있습니다.현재 양식에서 특정 유형의 값을 찾으려면 목록을 반복하여 일치하는 '유형' 키가 포함된 딕트를 찾은 다음 해당 항목 요소를 가져와야 합니다.1개 항목 딕트 목록 대신 단일 딕트를 사용하면 마스터 딕트에 대한 단일 키 검색으로 특정 유형의 항목을 찾을 수 있습니다.용사를 합니다.groupby
다음과 같이 표시됩니다.
result = {}
for key,valuesiter in groupby(input, key=sortkeyfn):
result[key] = list(v[0] for v in valuesiter)
result
이 딕트를 와 유사함).res
@Kenny 기본령의 기본 TM의 답변):
{'NOT': ['9085267', '11788544'],
'ETH': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'],
'KAT': ['11013331', '9843236']}
(이 값을 한 줄로 줄이려면 다음 작업을 수행할 수 있습니다.
result = dict((key,list(v[0] for v in valuesiter)
for key,valuesiter in groupby(input, key=sortkeyfn))
또는 새로운 fangled 딕트 이해 양식을 사용합니다.
result = {key:list(v[0] for v in valuesiter)
for key,valuesiter in groupby(input, key=sortkeyfn)}
이 답변은 @PaulMcG의 답변과 비슷하지만 입력을 정렬할 필요는 없습니다.
프로그래밍을 은,groupBy
로 쓸 수은 포함하지 않음!)는 달리.itertools.groupby
입력을 정렬할 필요가 없습니다.
from functools import reduce # import needed for python3; builtin in python2
from collections import defaultdict
def groupBy(key, seq):
return reduce(lambda grp, val: grp[key(val)].append(val) or grp, seq, defaultdict(list))
:... or grp
에 시대에lambda
이것을 위한 것입니까?reduce()
일을 하기 위해서 ,lambda
첫 번째 인수를 반환해야 합니다. 왜냐하면list.append()
항상 되돌아옴None
그or
항상 돌아올 것입니다.grp
즉, 람다는 하나의 표현식만 평가할 수 있다는 파이썬의 제약을 피하기 위한 해킹입니다.)
지정된 함수를 평가하여 키를 찾은 딕트와 값이 원래 순서의 원래 항목 목록인 딕트를 반환합니다.OP의 예로, 이것을 다음과 같이 부릅니다.groupBy(lambda pair: pair[1], input)
다음 dict를 반환합니다.
{'KAT': [('11013331', 'KAT'), ('9843236', 'KAT')],
'NOT': [('9085267', 'NOT'), ('11788544', 'NOT')],
'ETH': [('5238761', 'ETH'), ('5349618', 'ETH'), ('962142', 'ETH'), ('7795297', 'ETH'), ('7341464', 'ETH'), ('5594916', 'ETH'), ('1550003', 'ETH')]}
그리고 @PaulMcG의 답변에 따르면 OP가 요청한 형식은 목록 이해로 포장하여 찾을 수 있습니다.이렇게 하면 됩니다.
result = {key: [pair[0] for pair in values],
for key, values in groupBy(lambda pair: pair[1], input).items()}
저는 또한 판다들이 단순한 그룹을 이루는 것을 좋아했습니다.강력하고 단순하며 대용량 데이터 세트에 가장 적합합니다.
result = pandas.DataFrame(input).groupby(1).groups
다음 함수는 임의의 길이의 튜플을 인덱스가 있는 키로 빠르게(정렬할 필요가 없음) 그룹화합니다.
# given a sequence of tuples like [(3,'c',6),(7,'a',2),(88,'c',4),(45,'a',0)],
# returns a dict grouping tuples by idx-th element - with idx=1 we have:
# if merge is True {'c':(3,6,88,4), 'a':(7,2,45,0)}
# if merge is False {'c':((3,6),(88,4)), 'a':((7,2),(45,0))}
def group_by(seqs,idx=0,merge=True):
d = dict()
for seq in seqs:
k = seq[idx]
v = d.get(k,tuple()) + (seq[:idx]+seq[idx+1:] if merge else (seq[:idx]+seq[idx+1:],))
d.update({k:v})
return d
질문의 경우 그룹화할 키의 인덱스는 1이므로 다음과 같습니다.
group_by(input,1)
기브즈
{'ETH': ('5238761','5349618','962142','7795297','7341464','5594916','1550003'),
'KAT': ('11013331', '9843236'),
'NOT': ('9085267', '11788544')}
당신이 요청한 출력은 정확하지 않지만, 당신의 필요에 맞는 것일 수도 있습니다.
result = []
# Make a set of your "types":
input_set = set([tpl[1] for tpl in input])
>>> set(['ETH', 'KAT', 'NOT'])
# Iterate over the input_set
for type_ in input_set:
# a dict to gather things:
D = {}
# filter all tuples from your input with the same type as type_
tuples = filter(lambda tpl: tpl[1] == type_, input)
# write them in the D:
D["type"] = type_
D["itmes"] = [tpl[0] for tpl in tuples]
# append D to results:
result.append(D)
result
>>> [{'itmes': ['9085267', '11788544'], 'type': 'NOT'}, {'itmes': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'itmes': ['11013331', '9843236'], 'type': 'KAT'}]
정확한 작업에 대한 애드혹 코드를 생성하고 동적 코드 생성을 허용하는 convtools 라이브러리를 사용할 수 있습니다.
from convtools import conversion as c
# grouping by second elements of tuples;
# aggregate defines the schema of the expected output elements
converter = c.group_by(c.item(1)).aggregate({
"type": c.item(1),
"items": c.ReduceFuncs.Array(c.item(0)),
}).gen_converter()
# now you have a function which does what you asked,
# store it somewhere for further reuse
converter(input_data)
다음 스니펫을 따르는 것도 원하는 결과를 얻을 수 있는 방법입니다.
res = []
dict1 = {}
for item in input:
if item[1] not in dict1:
dict1[item[1]] = [item[0]]
elif item[1] in dict1:
dict1[item[1]].append(item[0])
for k, v in dict1.items():
res.append({"type": k, "items": v})
# res = [ { type:'KAT', items: ['11013331', '9843236'] },{ type:'NOT', items: ['9085267', '11788544'] },{ type:'ETH', items: ['5238761', '962142', '7795297', '7341464', '5594916', '1550003'] }]
이것은 매우 효율적이지는 않지만, 파이썬적입니다.기본적으로 그룹 값 집합을 가져와서 개별 그룹을 계산한 다음 각 그룹에 대해 해당 그룹에 있는 항목을 가져옵니다.
[
{
"type": group,
"items": [item[0] for item in input if item[1] == group]
}
for group in {item[1] for item in input}
]
언급URL : https://stackoverflow.com/questions/3749512/python-group-by
'programing' 카테고리의 다른 글
Oracle SQL*Plus에서 LOB 열의 전체 내용을 표시하는 방법은 무엇입니까? (0) | 2023.06.17 |
---|---|
Typescript/JSX with React에서 화살표 기능이 있는 제네릭을 사용하는 방법은 무엇입니까? (0) | 2023.06.17 |
Firebase Firestore 타임스탬프를 날짜(Swift)로 변환하시겠습니까? (0) | 2023.06.17 |
C#에서 더 큰 문자열에서 하위 문자열의 모든 위치 찾기 (0) | 2023.06.17 |
jquery: ID가 특정 패턴인 요소 찾기 (0) | 2023.06.17 |