(연습문제) 대소문자변환

연습문제 : 대소문자 변환하기

입력받은 문자열의 대소문자를 반전하여 출력하는 프로그램을 작성하시오.

입력받은 각 글자의 문자 코드가 ‘a’ … ‘z’ 사이에 있으면 소문자, ‘A’~’Z’ 사이에 있으면 대문자이다. 그리고 그 변환은 해당 코드값에 a - A를 더하거나 빼주면 된다.

먼저 대소문자의 범위를 찾아보자.

print("azAZ".utf8.map(Int.init))
//=> [97, 122, 65, 90]

즉 문자 코드가 97~122 구간에 있으면 소문자, 65~90 구간에 있으면 대문자이다. 소문자->대문자 변환은 32를 빼고, 반대의 변환은 32를 더한다.

문자 코드 값으로 다시 문자를 만드는 방법은 다음과 같다.

  1. 문자열은 [Character] 타입으로 만들 수 있다.
  2. 코드값으로 Character 인스턴스를 만들기 위해서는 Int 값을 UnicodeScalar 값으로 변환하면 된다.

즉, 다음과 같이 변경할 수 있다.

let arr = [97, 122, 65, 90]
let str = String(arr.map{ Character(UnicodeScalar($0)) })
print(str)
//=> "azAZ"

전체 코드는 다음과 같다.

if let s = readLine(), case let u = s.utf8.map(Int.init) {
    let h: Int -> Int = { n in
        switch n {
        case 97...122: return n - 32
        case 65...96: return n + 32
        default: return n
        }
    }
    let result = String(u.map{ Character(UnicodeScalar(h($0))) })
    print(result)
}

위의 switch 문은 간단히 삼항 연산자의 중첩으로 쓸 수 있다. 범위(Range<Int>)에 특정 값이 있는지는 패턴매칭으로 찾는데, 패턴매칭은 연산자 ~=를 쓰므로 다음과 같이 코드를 줄일 수 있다.

/* shorter version */
if let s = readLine(), case let u = s.utf8.map(Int.init) {
    let h: Int -> Int = { n in return 97...122 ~= n ? n - 32 : 65...96 ~= n ? n + 32 : n }
    let result = String(u.map{ Character(UnicodeScalar(h($0))) })
    print(result)
}

하스켈 풀이

하스켈의 경우, Data.Char 모듈에 isUpper, toUpper, toLower 함수가 정의되어 있으므로 이를 이용할 수 있다.

import Data.Char
main = interact (map f) where f c = if isUpper c then toLower c else toUpperc

interact 함수는 String -> String -> IO () 타입의 함수로 입력받은 문자열을 처리해주는 함수를 받아서 입력과 출력을 연결해주는 함수이다. 즉,

main = getLine >= (\xs -> putStrLn . (map f) $ xs)

를 줄인 것이다.

project euler 41

오일러 프로젝트 41 번

1부터 n까지의 숫자를 하나씩만 써서 만든 n자리 숫자를 팬디지털(pandigital)이라고 부릅니다.
2143은 4자리 팬디지털인데, 이 수는 동시에 소수이기도 합니다.

n자리 팬디지털 소수 중에서 가장 큰 수는 무엇입니까?

http://euler.synap.co.kr/prob_detail.php?id=41

9자리 팬디지털 숫자의 각 자리 숫자의 합은 45로 이는 3의 배수가 됨을 알 수 있다. 8자리 팬디지털 숫자의 경우에 각 자리 수의 합 역시 3의 배수이다.

따라서 가장 큰 팬디지털 소수는 최대 7자리에서부터 있을 수 있다. 이는 1~7의 숫자를 순열로 만들어 큰 숫자부터 소수인지 검사해 내려가면 된다.

from functools import reduce

def is_prime(n):
    if n < 2:
        return False
    if n is 2 or n is 3:
        return True
    if n %2 == 0 or n % 3 == 0:
        return False
    if n < 9:
        return True
    k = 5
    l = n ** 0.5
    while k <= l:
        if n % k == 0 or n % (k+2) == 0:
            return False
        k += 6
    return True

def factorial(n):
    if n < 2:
        return 1
    return reduce(lambda x,y: x*y, range(1, n+1), 1)

def perms(n, ls):
    if n is 0:
        return ls
    l = len(ls)
    n = n % factorial(l)
    q, r = divmod(n, factorial(l-1))
    return [ls[q]] + perms(r, ls[:q] + ls[q+1:])

def list_to_int(ls):
    return reduce(lambda x,y: x*10 + y, ls, 0)

def e41():
    a = [7,6,5,4,3,2,1]
    l = factorial(7)
    s = []
    for i in range(l, 0, -1):
        n = list_to_int(perms(i, a))
        if is_prime(n):
            print(n)
            return

%time e41()

# 1234657
# Wall time: 1e+03 µs