[파이썬3.0] 데이터 정렬

프로그램 언어/파이썬|2014. 6. 24. 22:25

데이터 정렬


 


우리가 사는 사회는 정렬을 좋아한다.

데이터도 다르지 않다.

그러나 데이터를 입력할 때 정렬된 형태로 입력하지는 않는다.
비정돈된 데이터를 불러와서 정렬작업을 하여 원하는 결과를 도출해야 한다
이번에는 바로 그 정렬을 하는 것을 해보자. 

 with open('james.txt') as 제임스파일:
    data=제임스파일.readline()
제임스 = data.strip().split(',')

with open('julie.txt') as 줄리파일:
    data=줄리파일.readline()
줄리 = data.strip().split(',')

with open('mikey.txt') as 미키파일:
    data=미키파일.readline()
미키 = data.strip().split(',')

with open('sarah.txt') as 사라파일:
    data=사라파일.readline()
사라 = data.strip().split(',')

print(제임스)
print(줄리)
print(미키)
print(사라)


>>>
['2-34', '3:21', '2.34', '2.45', '3.01', '2:01', '2:01', '3:10', '2-22']
['2.59', '2.11', '2:11', '2:23', '3-10', '2-23', '3:10', '3.21', '3-21']
['2:22', '3.01', '3:01', '3.02', '3:02', '3.02', '3:22', '2.49', '2:38']
['2:58', '2.58', '2:39', '2-25', '2-55', '2:54', '2.18', '2:55', '2:55']

위 데이터는 시 분 단위로 기록되어 있는 시간데이터이다.
보면 정렬이 되지 않았다.

그럼 이제 저 데이터를 정렬된 형태로 출력을 해보자.

먼저 정렬 방법을 알아보자.

  1. 원본 정렬
  2. 사본 정렬

이렇게 두가지가 있다.

1. 원본 정렬(In-place-sorting)
데이터를 가져와서 지정한 순서대로 정렬을 하고, 원래의 데이터를 정렬된 데이터로 대체하는 것을 의미한다. 즉 원본 자체가 정렬된 형태로 변경되는 것이다.
사용하는 방법은
리스트의 sort()메서드를 사용하면 된다.
기본적으로 오름차순으로 정렬 reverse=True 를 인자로 주면 내림차순으로 정렬.

2. 사본 정렬(Copied sorting)
데이터를 가져와서 지정한 순서대로 정렬
정렬된 것을 반환한다.
즉, 이 방법은 원본 데이터에는 영향이 없고 말그대로 사본을 만들어서 그 복사된 데이터를 반환시키는 것이다.
사용 방법
sorted() 내장 함수를 이용
기본적으로 오름차순, reverse=True 인자로 내림차순으로 변경가능.
그러나 원본 정렬과 달리 복사하기 때문에 복사한(정렬된) 데이터를 받아줄 객체가 필요하다.
xxxx=sorted(원본) 형태가 된다.

그림으로 표현하여 비교하면,




방금 전 정렬되지 않은 것을 정렬해 해보자.
>>>
['2-34', '3:21', '2.34', '2.45', '3.01', '2:01', '2:01', '3:10', '2-22']
['2.59', '2.11', '2:11', '2:23', '3-10', '2-23', '3:10', '3.21', '3-21']
['2:22', '3.01', '3:01', '3.02', '3:02', '3.02', '3:22', '2.49', '2:38']
['2:58', '2.58', '2:39', '2-25', '2-55', '2:54', '2.18', '2:55', '2:55']

정렬 전이다.

정렬을 위한 코드
ex_sorting.py

with open('james.txt') as 제임스파일:
    data=제임스파일.readline()
제임스 = data.strip().split(',')     #메서드 연속 호출(method chaining) 왼쪽에서 부터 오른쪽으로 동작.

with open('julie.txt') as 줄리파일:
    data=줄리파일.readline()
줄리 = data.strip().split(',')

with open('mikey.txt') as 미키파일:
    data=미키파일.readline()
미키 = data.strip().split(',')

with open('sarah.txt') as 사라파일:
    data=사라파일.readline()
사라 = data.strip().split(',')

print(sorted(제임스))
print(sorted(줄리))
print(sorted(미키))
print(sorted(사라))# sorted() 함수를 이용한 방법.
사라.sort()# 리스트의 sort() 메서드를 사용한 방법.
print(사라)

위에 코드를 보면 data.strip().split(',') 을 볼 수 있는데, 메서드가 연속해서 사용되었다.
이것을 메서드 연속호출이라고 하며 작동 순서는 왼쪽->오른쪽 으로 동작한다.
메서드만 연속 호출이 될까??
아니다.
함수도 연속 호출이 가능하다.
print(sorted(사라)) 처럼 함수도 연속해서 사용을 했다.
이럴 경우에는 메서드와 반대로 오른쪽->왼쪽 으로 동작한다.

실행 결과
>>>
['2-22', '2-34', '2.34', '2.45', '2:01', '2:01', '3.01', '3:10', '3:21']
['2-23', '2.11', '2.59', '2:11', '2:23', '3-10', '3-21', '3.21', '3:10']
['2.49', '2:22', '2:38', '3.01', '3.02', '3.02', '3:01', '3:02', '3:22']
['2-25', '2-55', '2.18', '2.58', '2:39', '2:54', '2:55', '2:55', '2:58']
['2-25', '2-55', '2.18', '2.58', '2:39', '2:54', '2:55', '2:55', '2:58']

앞자리수만 보면 정렬은 된듯하지만....
제대로 되진 않았다.

정렬을 할때 파이썬은 문자열로 정렬한다. 
무슨말인가 하면, 2는 3보다 앞에 있는 문자이고 '-'는 '.'보다 앞에 있고 '.'는 ':'보다 앞에 있다는 것이다.

여기서 제대로되 정렬이 이루어지지 않은 것은 데이터가 일관성있는 형태가 아니기 때문인다.
사람이 보기에는 모두 같은 의미이지만 컴퓨터는 아스키코드값과 같은 형태로 되기에 다른 의미라고 판단 할 수 있다.

제대로 정렬을 하기 위해서는 데이터를 일관성있게 해주는 작업을 해줘야 한다.

sanitize.py
 
def 동일화(time_string):
    if '-' in time_string:
        splitter='-'
    elif ':' in time_string:
        splitter=':'
    else:
        return(time_string)

    (mins,secs) = time_string.split(splitter)
    return(mins+'.'+secs)

이 함수가 바로 리스트에 있는 ':'와 '-'을 '.'로 변형시켜준다.

ex_sorting_complete.py

with open('james.txt') as 제임스파일:
    data=제임스파일.readline()
제임스 = data.strip().split(',')

with open('julie.txt') as 줄리파일:
    data=줄리파일.readline()
줄리 = data.strip().split(',')

with open('mikey.txt') as 미키파일:
    data=미키파일.readline()
미키 = data.strip().split(',')

with open('sarah.txt') as 사라파일:
    data=사라파일.readline()
사라 = data.strip().split(',')

done_제임스=[] # 데이터를 같은 형태로 변한 것을 담을 객체
done_줄리=[]
done_미키=[]
done_사라=[]

for each_t in 제임스:
    done_제임스.append(동일화(each_t))#만든 함수를 이용해 리스트내의 문자열을 일정한 형태로 변경
for each_t in 줄리:
    done_줄리.append(동일화(each_t))
for each_t in 미키:
    done_미키.append(동일화(each_t))
for each_t in 사라:
    done_사라.append(동일화(each_t))

print(sorted(done_제임스))
print(sorted(done_줄리))
print(sorted(done_미키))
print(sorted(done_사라))

 

실행 결과 

>>>
['2.01', '2.01', '2.22', '2.34', '2.34', '2.45', '3.01', '3.10', '3.21']
['2.11', '2.11', '2.23', '2.23', '2.59', '3.10', '3.10', '3.21', '3.21']
['2.22', '2.38', '2.49', '3.01', '3.01', '3.02', '3.02', '3.02', '3.22']
['2.18', '2.25', '2.39', '2.54', '2.55', '2.55', '2.55', '2.58', '2.58']

드디어 보기 깔끔하게 정렬되어 나온다.

그럼 끝?

위에 코드가 생각보단 길다는 생각은 안드나???
중복된 것들이 많아서 복잡하진 않지만 길어져서 수정작업을 하거나 할때 귀찮거나 힘들 수 있다.

지능형 리스트

지능형 리스트는 다음과 같은 과정을 거치는 리스트를 말한다.

  1. 변환된 데이터를 보관할 리스트를 새로 만들고
  2. 원래 리스트의 모든 데이터 항목을 나열
  3. 나열하면서 각 데이터 항목을 변환
  4. 변환된 데이터를 새 리스트에 추가

위에 코드에서 보면
done_사라=[]
for each_t in 사라:
    done_사라.append(동일화(each_t))
부분을 지능형 리스트로 병형해서 사용하면 편한다.

done_사라=[동일화(each_t) for each_t in 사라]


위에 코드보다 훨씬 간결해졌다. 
지능형 리스트를 사용하면 이러한 점에서 분명 이득을 볼 것이다.

지능형 리스트는 리스트 안에 함수나 조건이나 반복문들을 사용하는 것으로
예를 들면
>>> 분=[1,2]
>>> 초=[m*60 for m in 분]
>>> 초
[60, 120]

와 같다. 리스트 메서드도 사용이 가능하고 연속호출도 가능하다.

이것이 간단하고 좋은 것 같은데 왜 두개가 공존할까?

그것은 둘다 쓰임세가 다르기 때문이다. 좀 더 융통성있는 것은 리스트 나열(기존방법)이다.

참고 : headfirst python, 파이썬3 바이블


댓글()