2014-03-24 4 views
1

저는 Racket/Scheme에서 정수 목록을 제공하는 함수를 작성하려고합니다. 그런 다음 두 개의 하위 목록 (짝수와 홀수에 대해 하나씩)으로 정렬해야합니다. 나는 라켓을하기가 너무 쉽다.리스트를 다루는 것에 대한 기초를 가지고 있지만 두 개의 서브리스트를 정의하고 각각에 숫자를 매기는 방법을 알아낼 수는 없다.라켓 - 짝수 및 홀수 숫자 분리?

(define (segregate lst) 
     (if (empty? lst) 
      '() 
      (if (even? (car a lst)) 
       (append (car alst) (segregate (cdr alst)))) 

을 그리고 거기에서 내가 붙어있어 :

이것은 내가 지금까지있는 것입니다. 조건이 충족되면 짝수가 하나의 목록으로 정렬됩니다. 하지만 이상한 숫자가 필요합니다. 이 조건의 else 문은 그러한 홀수를 제공하지만 별도의 목록으로 가져 오는 방법을 알지 못합니다.

교수님이 어떤 이유로 든 사무실에 없기 때문에 제가이 사이트에서 실제로 질문을 한 것은 이번이 처음입니다.

+0

이 코드 foldr 사용하는 것입니다. 'car'는 정확히 하나의 인수를 기대하지만,'(car lst)'를 얻었습니다. 또한'(자동차 우선)'과'(cdr alst)'도 있지만'alst' 변수는 없습니다. –

+0

포맷이 개선되었습니다. 이제는 더 명확해질 것입니다. – leppie

답변

1

따라서 함수가 두 개의 목록을 반환해야합니다. 맞습니까? 기본 케이스는 두 개의 빈 목록을 반환해야하며 재귀 적 경우에 따라 관련 항목을 채 웁니다. 여기에 몇 가지 골격 코드합니다 (<???>에 기입)이있다 :

(define (odds-and-evens lst) 
    (if (null? lst) 
     (values '() '()) 
     (let-values (((odds evens) (odds-and-evens (cdr lst)))) 
     (cond ((odd? (car lst)) (values (cons <???> <???>) <???>)) 
       ((even? (car lst)) (values <???> (cons <???> <???>))) 
       (else (values odds evens)))))) 
+0

네, 고마워요. 지금까지 let-values ​​함수를 알지 못했습니다. – user3451298

1

크리스 'let-values -version 매운이지만, 나는 그것이 꼬리 재귀 만들기 위해 이런 식으로 작성된 것입니다 : 심지어

(define (split left? lst) 
    (let loop ((lst lst) (a '()) (b '())) 
    (if (null? lst) 
     ;; you don't need to use values. `cons` or `list` are sometimes preferred 
     (values (reverse a) (reverse b)) 
     (let ((e (car lst))) 
      (if (left? e) 
       (loop (cdr <???>) (cons <???> <???>) <???>) 
       (loop (cdr <???>) <???> (cons <???> <???>))))))) 

(split odd? '(1 2 3 4 ...)) 
; ==> 
; (1 3 ...) 
; (2 4 ...) 

두리스트를 두 번 통과 시키지만 (하나는 분리를하고 다른 하나는 그 반대의 작업을 수행합니다), 여전히 여러 번 빠르고 IMO는 더 간단합니다.

주문에 신경 쓰지 않는다면 reverse 단계를 건너 뛰면 훨씬 빨라집니다.

1

위의 코드는 지옥으로 혼돈되어 있습니다. 라켓은 매우 간단한 언어이며, 코드를 읽는 동안 코드가하는 일을 이해하기위한 것입니다. 이 문제에 꼬리 재귀를 사용할 수 있습니다.

A의 첫 번째 요소를 분석하여 필요한 위치에 놓은 다음 A가 비어있을 때까지 함수를 다시 호출합니다.

(define segregate 
    (lambda (A o e) ;A is the list of integers, o is the list of odds and e is for evens. 
     (cond ((empty? A) (list o e)) 
      ((even? (car A)) (segregate (cdr A) o (append e (car A))) 
      (else (segregate (cdr A) (append o (car A)) e))))) 
+1

감사합니다. 분명히 초보자는 자신의 질문에 대답 할 수는 없지만 모든 부울 함수를 기반으로 목록을 추출하는 중간 함수를 작성하여 솔루션을 찾은 다음 짝수 및 홀수 함수를 호출하는 두 개의 하위 목록이있는 목록을 작성합니다 . – user3451298

+0

그건 실제로 좋은 접근 방법입니다. 당신은 코드의 추상화를 강화하고 있습니다. 잘 했어. –

+1

버전이 매우 비효율적입니다. 단점에 기반한리스트는'cons' (O (1) 연산)를 사용하여 오른쪽에서 왼쪽으로 작성됩니다. 'append' (각 호출에 대해 O (n))를 사용하여 왼쪽에서 오른쪽으로 빌드하려는 시도는 잘못된 방법입니다.이렇게하려면 두 가지 방법이 있습니다. 왼쪽 접기를 사용하고 그 결과를 반대로 바꿀 수 있습니다. 이것이 실 웨스터의 해결책입니다. 또는 오른쪽 폴드를 사용할 수 있습니다. 이것이 바로 내 솔루션입니다. –

1

이 내장되어 사용 partition :

(define (segregate lst) 
    (let-values ([(e o) (partition even? lst)]) 
    (list e o))) 
+1

아니요, 내 해결책은'let-values' 또는 변환 목록없이 직접'파티션 '입니다. ;-) 게다가리스트로 변환하고 싶다면'call-with-values'를 직접 사용하는 것이 더 효율적일 것입니다 : (값 호출 (lambda() (파티션 even?))리스트)' –

+0

죄송합니다. 답변을 작성할 때만 코드를 스캔했습니다. 네가 옳아. 고쳤다. – caisah

1

또 다른 대안은 순간에 실행되지 않습니다

(define (odd-even xs) 
    (foldr (lambda (x b) 
      (if (odd? x) 
       (list (cons x (first b)) (second b)) 
       (list (first b) (cons x (second b))))) '(()()) xs)) 

[email protected]> (odd-even '(1 2 3 4 5 6 7)) 
'((1 3 5 7) (2 4 6))