2009-12-16 2 views
6

제목이 말하는 것과 비슷합니다. 나는 이렇게 정수리스트를 가지고있다 : [1,2,3]. 이것을 정수 123으로 변경하고 싶습니다. 첫 번째 생각은 concat 이었지만 잘못된 유형이므로 여러 가지를 시도했지만 일반적으로 같은 목록을 반환합니다. 어떤 도움이라도 대단히 감사합니다.정수 목록을 haskell의 하나의 Int (concat와 같은)로 변환하십시오.

또한은 유형이 Integer이고 putStr이 수행하지 않는 것을 제외하고는 올바른 것을 인쇄하는 방법을 찾았습니다 (putStr).

답변

21

당신은 목록의 모든 요소를 ​​결합하는 foldl를 사용할 수 있습니다

fromDigits = foldl addDigit 0 
    where addDigit num d = 10*num + d 

addDigit 기능은 왼쪽 하나에서 시작, 숫자, 다른 후 하나를 추가 할 수 foldl에 의해 호출됩니다.

*Main> fromDigits [1,2,3] 
123 

편집 : 몇 가지 값을 축적하는 요소를 추가, 왼쪽에서 오른쪽으로
foldl는 목록을 안내합니다.

이 경우 foldl, 0의 두 번째 인수는 프로세스의 시작 값입니다. 첫 번째 단계에서 시작 값은 addDigit 0 1을 호출하여 목록의 첫 번째 요소 인 1과 결합됩니다. 결과는 10 * 0 + 1 = 1이됩니다. 다음 단계에서이 1은 목록의 두 번째 요소 인 addDigit 1 2과 결합되어 10 * 1 + 2 = 12가됩니다. 그러면 목록의 세 번째 요소와 결합됩니다 , addDigit 12 3에 의해 10 * 12 + 3 = 123이됩니다.

0을 곱하면 무의미하게 첫 번째 단계가됩니다. 다음 단계에서 실제로 "0"이 아닌 "0"으로 새 숫자를 추가하려면 곱셈이 실제로 필요합니다. 번호가 누적됩니다.

+7

또는 쿨러 포인트 무료 - fromDigits = foldl ((+). (* 10)) 0 : –

+0

굉장! 완벽하게 작동합니다. 이것은 내가해야 할 일이라고 생각했던 것이었지만, 당신은 내가 할 수있는 것보다 훨씬 좋았습니다! – Paul

+0

그래도 작동하지만 addDigit 파트가 어떻게 작동하는지 정확히 알 수는 없습니다. 나는 foldl이 함수를 취하고리스트가리스트의 모든 요소에서 그것을한다는 것을 안다. 그러나 addDigit은 0 (num)을 10으로 곱한 다음 요소를 추가하는 것처럼 보인다. 내가 빠졌어? – Paul

9

당신은 숫자의 문자열 표현을 concat 다음 read을 다시과 같이 수 :

joiner :: [Integer] -> Integer 
joiner = read . concatMap show 
+2

이것은'[12,34]'를'1234'로 바꿉니다 - sth와 달리'154' 또는 Chris의 에러로 바뀝니다. OP의 원하는 동작이 충분히 지정되지 않았습니다. – ephemient

+0

sth의 작품은 오직 한 자리 숫자 만 사용하기 때문에 작동합니다. 이것은 또한 내가 일하고 싶습니다 방법이지만 누군가가 정확히 어떻게 addDigit sth의 작품을 설명 할 수 있을까? – Paul

2

사용 read을 또한 intToDigit :

joinInt :: [Int] -> Int 
joinInt l = read $ map intToDigit l 

는 장점 (불이익)가 여러 자리 숫자에 대한 푸킹

0

수를 인쇄하는 방법에 관해서는, 대신에

putStr n 

는 추론이 그 putStr 할 수있는 유일한 인쇄 문자열입니다

putStr (show n) 

보십시오. 따라서 번호를 전달하기 전에 숫자를 문자열로 변환해야합니다.

Prelude의 print 함수를 사용해 볼 수도 있습니다. 이것은 문자열뿐만 아니라 "보여줄 수있는"(클래스 Show의 모든 인스턴스) 인쇄 할 수 있습니다. 그러나 print n은 (대략) 이 아니고 putStr (show n)이 아닙니다.

+0

그건 그렇고, 이것은 정말로 별개의 질문이되어야합니다 ... –

1

또 다른 아이디어는 말하기 것입니다 : 마지막 숫자는 1, 마지막 숫자는 10, 그 전에는 100으로 계산합니다. 그래서 숫자 목록을 숫자로 변환하려면, 역순으로 (뒤에서 시작하기 위해) 숫자를 상응하는 10의 거듭 제곱과 곱하고 그 결과를 더해야합니다.

는 두 목록 사용 zipWith (*)의 해당 숫자를 곱하고 sum를 사용, 모든 것을 함께 추가 iterate (*10) 1를 (! GHCi 또는 포옹에 그것을 시도), 사용할 수있는 10 세의 힘을 얻기 위해, reverse 사용 목록을 반대합니다 - 정말 몇 가지 라이브러리 함수를 아는 데 도움이됩니다!

fromDigits [1,2,3,4] 
    ==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....] 
    ==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....]) 
    ==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000] 
    ==> 4 + 30 + 200 + 1000 
    ==> 1234 

그러나,이 솔루션으로 인해 reverse에 대한 호출에 당신이 구축하고 있기 때문에, foldl 가진 것보다 느립니다 : 함께 비트를 넣어, 당신은 평가의

fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1)) 

예를 얻을 수 열의 그 힘은 그들을 직접적으로 다시 사용하는 것입니다. 더하기 측면에서, 숫자를 짓는이 방법은 사람들이 일반적으로 생각하는 방식 (더 이상 나는하지 않습니다!)에 가장 가까운 반면, foldl -solutions은 Horner's rule을 사용합니다.

+0

그 목록은 GHC에서 유효한 구문입니까? 제가 여기에있는 것은 포옹입니다. 그리고 그것은 확실히 작동하지 않습니다. – Chuck

+0

아니요, 그 목록은'iterate (* 10) 1'의 결과 (일부)를 설명하기위한 것입니다. GHC에서도 작동하지 않습니다. – yatima2975

-2

저는 하스켈의 전문가는 아니지만, 다른 외부 기능을 사용하지 않는이 문제에 대한 해결책을 생각해 볼 수있는 가장 쉬운 방법입니다.

ConcatDigits :: [Int] -> Int 
ConcatDigits [] = 0 
ConcatDigits xs = ConcatReversed (ReverseDigits xs) 1 

ReverseDigits :: [Int] -> [Int] 
ReverseDigits [] = [] 
ReverseDigits (x:xs) = (ReverseDigits xs) : x 

ConcatReversed :: [Int] -> Int -> Int 
ConcatReversed [] d = 0 
ConcatReversed (x:xs) d = (x*d) + ConcatReversed xs (d*10) 

당신이 볼 수 있듯이, 나는 당신이 숫자 목록을 연결하려고한다고 가정했습니다. 혹시 이것이 당신의 경우가 아니라면, 나는 이것이 작동하지 않을 것이라고 확신합니다. 내 용액에 :(

, I 원래리스트 반전 ReverseDigits라는 함수를 정의한 우선. [3,2,1]

실시 예 [1,2,3]의 후 즉, 목록의 첫 번째 숫자가 10 자리의 결과 인 숫자와 숫자 d의 목록을 취하는 ConcatReversed 함수를 사용합니다. 목록이 비어 있으면 0을 반환하고 그렇지 않으면 첫 번째 숫자를 반환합니다. 목록 시간 d를 더한리스트의 나머지와 D 10 배를 통과 ConcatReversed를 호출합니다.

코드를 희망 나는 불쌍한 내 영어 설명이 매우 도움이 아니었다 생각하기 때문에, 그 자체에 대한 이야기.

+0

-1 : 생성자가 아닌 함수는 소문자입니다. 또한 매우 직관적 인 IMO도 아닙니다. –

+0

나는 이것이 완벽하게 유효한 대답이라고 생각한다. 나는 코딩 규칙을 모르는 경우 나도 하스켈의 전문가가 아니므로 나를 죽이지는 않는다고 분명했다. – Fede

관련 문제