2012-04-29 17 views
11

में एक सूची का विभाजन करना मैं एक आवेदन में रैकेट में काम कर रहा हूं मुझे संख्याओं की एक सूची लेने और सूची को लगातार संख्याओं की उप-सूचियों में विभाजित करने की आवश्यकता है: (वास्तव में, मैं वास्तव में एक नंबर और कुछ डेटा से मिलकर जोड़े विभाजन है, लेकिन सिद्धांत एक ही है)रैकेट

यानी अगर मेरे प्रक्रिया chunkify तो कहा जाता है:।

(chunkify '(1 2 3 5 6 7 9 10 11)) -> '((1 2 3) (5 6 7) (9 10 11)) 
(chunkify '(1 2 3)) -> '((1 2 3)) 
(chunkify '(1 3 4 5 7 9 10 11 13)) -> '((1) (3 4 5) (7) (9 10 11) (13)) 
(chunkify '(1)) -> '((1)) 
(chunkify '()) -> '(()) 

आदि

मैं के साथ आए हैं रैकेट में निम्नलिखित:

#lang racket 
(define (chunkify lst) 
    (call-with-values 
    (lambda() 
    (for/fold ([chunk '()] [tail '()]) ([cell (reverse lst)]) 
     (cond 
     [(empty? chunk)      (values (cons cell chunk) tail)] 
     [(equal? (add1 cell) (first chunk)) (values (cons cell chunk) tail)] 
     [else (values (list cell) (cons chunk tail))]))) 
    cons)) 

यह सिर्फ ठीक काम करता है, लेकिन मैं रैकेट की अभिव्यक्ति दी सोच रहा हूँ अगर वहाँ ऐसा करने का एक और अधिक सरल आसान तरीका नहीं है, "कॉल-साथ-मूल्यों" से छुटकारा पाने के किसी तरह और प्रक्रिया आदि में सूची को उलट करने की आवश्यकता, शायद कुछ अलग तरीके से अलग है।

मेरा पहला प्रयास "The Little Schemer" में एक कलेक्टर के साथ एक पैटर्न पर बहुत शिथिल आधारित था और कहा कि और भी कम ऊपर से स्पष्ट था:

(define (chunkify-list lst) 
(define (lambda-to-chunkify-list chunk) (list chunk)) 

(let chunkify1 ([list-of-chunks '()] 
       [lst lst] 
       [collector lambda-to-chunkify-list]) 
    (cond 
    [(empty? (rest lst)) (append list-of-chunks (collector (list (first lst))))] 
    [(equal? (add1 (first lst)) (second lst)) 
     (chunkify1 list-of-chunks (rest lst) 
       (lambda (chunk) (collector (cons (first lst) chunk))))] 
    [else 
     (chunkify1 (append list-of-chunks 
         (collector (list (first lst)))) (rest lst) list)]))) 

मैं क्या देख रहा हूँ कुछ सरल, संक्षिप्त और सरल है।

+0

यह "मेरे कोड की समीक्षा करें" नहीं है, न कि "मेरे कोड में क्या गलत है", इसलिए मुझे लगता है कि www.codereview.stackexchange.com –

उत्तर

4

यहां बताया गया है कि मैं यह कर चाहते हैं::

;; chunkify : (listof number) -> (listof (non-empty-listof number)) 
;; Split list into maximal contiguous segments. 
(define (chunkify lst) 
    (cond [(null? lst) null] 
     [else (chunkify/chunk (cdr lst) (list (car lst)))])) 

;; chunkify/chunk : (listof number) (non-empty-listof number) 
;;    -> (listof (non-empty-listof number) 
;; Continues chunkifying a list, given a partial chunk. 
;; rchunk is the prefix of the current chunk seen so far, reversed 
(define (chunkify/chunk lst rchunk) 
    (cond [(and (pair? lst) 
       (= (car lst) (add1 (car rchunk)))) 
     (chunkify/chunk (cdr lst) 
         (cons (car lst) rchunk))] 
     [else (cons (reverse rchunk) (chunkify lst))])) 

हालांकि यह अपने अंतिम परीक्षण मामले से सहमत नहीं: यह है कि अगर यह संक्षिप्त है तय करने के लिए आप पर निर्भर है

(chunkify '()) -> '() ;; not '(()), as you have 

मैं अपने उत्तर को और अधिक प्राकृतिक मानता हूं; यदि आप वास्तव में '(()) होने का उत्तर चाहते हैं, तो मैं chunkify का नाम बदलूंगा और एक रैपर लिखूंगा जो खाली मामले को विशेष रूप से संभालता है।

आप आपसी प्रत्यावर्तन से बचने के लिए पसंद करते हैं, आप कर सकते हैं सहायक समारोह के बजाय एक दूसरे मूल्य के रूप में बचे हुए सूची लौट उस पर chunkify बुलाने की, तो जैसे:

;; chunkify : (listof number) -> (listof (non-empty-listof number)) 
;; Split list into maximal contiguous segments. 
(define (chunkify lst) 
    (cond [(null? lst) null] 
     [else 
     (let-values ([(chunk tail) (get-chunk (cdr lst) (list (car lst)))]) 
      (cons chunk (chunkify tail)))])) 

;; get-chunk : (listof number) (non-empty-listof number) 
;;   -> (values (non-empty-listof number) (listof number)) 
;; Consumes a single chunk, returns chunk and unused tail. 
;; rchunk is the prefix of the current chunk seen so far, reversed 
(define (get-chunk lst rchunk) 
    (cond [(and (pair? lst) 
       (= (car lst) (add1 (car rchunk)))) 
     (get-chunk (cdr lst) 
        (cons (car lst) rchunk))] 
     [else (values (reverse rchunk) lst)])) 
+0

धन्यवाद रयान। अंतिम परीक्षण मामला अप्रासंगिक है इसलिए '() या' (()) ठीक है। मैंने बस इसे अंदर रखा क्योंकि मैंने इसे देखने के लिए परीक्षण किया था कि मुझे इसके लिए कुछ अजीब नहीं मिला। –

+0

फिर से धन्यवाद। आपसी पुनरावृत्ति वह पैटर्न है जिसे मैं ढूंढ रहा था लेकिन काफी समझ नहीं पाया। भागों की सूची में उन्हें सांत्वना देने के लिए भाग और दूसरे बनाने के लिए एक पुनरावृत्ति। –

3

मैं एक सरल, सीधा समाधान केवल आदिम सूची संचालन और पूंछ प्रत्यावर्तन (कोई values, let-values, call-with-values) के साथ एक एकल प्रक्रिया का उपयोग कर के बारे में सोच सकते हैं - और यह बहुत कुशल है। रिक्त सूची मामले को संभालने के लिए प्रारंभिकरण के दौरान कुछ if अभिव्यक्तियों को जोड़ने की लागत पर यह आपके सभी परीक्षण मामलों के साथ काम करता है।

(define (chunkify lst) 
    (let ((lst (reverse lst))) ; it's easier if we reverse the input list first 
    (let loop ((lst (if (null? lst) '() (cdr lst)))  ; list to chunkify 
       (cur (if (null? lst) '() (list (car lst)))) ; current sub-list 
       (acc '()))         ; accumulated answer 
     (cond ((null? lst)     ; is the input list empty? 
      (cons cur acc)) 
      ((= (add1 (car lst)) (car cur)) ; is this a consecutive number? 
      (loop (cdr lst) (cons (car lst) cur) acc)) 
      (else       ; time to create a new sub-list 
      (loop (cdr lst) (list (car lst)) (cons cur acc))))))) 
+1

धन्यवाद ऑस्कर, यह बहुत तेज़ था (कुछ ऐसा था मेरी पोस्ट से 40 मिनट)। जब मैं सोचता हूं कि मुझे अपने समाधान के साथ आने में कितना समय लगेगा :-) चीयर्स। –

3

फिर भी एक और तरीका यह करने के लिए ।

#lang racket 

(define (split-between pred xs) 
    (let loop ([xs xs] 
      [ys '()] 
      [xss '()]) 
    (match xs 
     [(list)     (reverse (cons (reverse ys) xss))] 
     [(list x)    (reverse (cons (reverse (cons x ys)) xss))] 
     [(list x1 x2 more ...) (if (pred x1 x2) 
            (loop more (list x2) (cons (reverse (cons x1 ys)) xss)) 
            (loop (cons x2 more) (cons x1 ys) xss))]))) 

(define (consecutive? x y) 
    (= (+ x 1) y)) 

(define (group-consecutives xs) 
    (split-between (λ (x y) (not (consecutive? x y))) 
       xs)) 


(group-consecutives '(1 2 3 5 6 7 9 10 11)) 
(group-consecutives '(1 2 3)) 
(group-consecutives '(1 3 4 5 7 9 10 11 13)) 
(group-consecutives '(1)) 
(group-consecutives '()) 
+0

धन्यवाद सोगार्ड, खासकर पैटर्न मिलान के उपयोग को दिखाने के लिए। –

1

मैं खेलना चाहता हूं।

कोर पर यह वास्तव में कुछ भी नहीं है जो की पेशकश से बहुत अलग है लेकिन यह इसे/फोल्ड लूप के संदर्भ में रखता है। मेरे पास लूप की तरह उगाया गया है क्योंकि मुझे लगता है कि वे अधिक "देखने योग्य" (आवश्यक रूप से पठनीय नहीं) कोड के लिए बनाते हैं।हालांकि, (आईएमओ - ओओएस) रैकेट/योजना के साथ सहज होने के शुरुआती चरणों के दौरान मुझे लगता है कि रिकर्सिव अभिव्यक्तियों के साथ रहना सर्वोत्तम है।

(define (chunkify lst) 
    (let loop ([lst lst] [last #f] [resint '()] [resall '()]) 
    (if (empty? lst) 
     (append resall (list (reverse resint))) 
     (begin 
      (let ([ca (car lst)] [cd (cdr lst)]) 
      (if (or (not last) (= last (sub1 ca))) 
       (loop cd ca (cons ca resint) resall) 
       (loop cd ca (list ca) (append resall (list (reverse resint)))))))))) 

यह भी पिछले परीक्षण मामले के लिए काम करता है:

(define (chunkify lst) 
    (define-syntax-rule (consecutive? n chunk)  
     (= (add1 (car chunk)) n)) 
    (if (null? lst) 
     'special-case:no-chunks 
     (reverse 
     (map reverse 
       (for/fold ([store `((,(car lst)))]) 
         ([n   (cdr lst)]) 
       (let*([chunk (car store)]) 
        (cond 
        [(consecutive? n chunk) 
         (cons (cons n chunk) (cdr store))] 
        [else 
         (cons (list n) (cons chunk (cdr store)))]))))))) 


(for-each 
(ƛ (lst) 
    (printf "input : ~s~n" lst) 
    (printf "output : ~s~n~n" (chunkify lst))) 
'((1 2 3 5 6 7 9 10 11) 
    (1 2 3) 
    (1 3 4 5 7 9 10 11 13) 
    (1) 
    ())) 
+0

बहुत धन्यवाद डीएलएम। रैकेट का उपयोग करना चीजों को करने के कई अलग-अलग तरीके हैं। मैं रयान के समाधान के साथ गया हूं लेकिन मैं "लगातार" पास करता हूं? एक प्रथम श्रेणी समारोह के रूप में। चूंकि मैं एप्लिकेशन में सूचियों की कई अलग-अलग प्रकार की सूचियों के साथ "चुंकिफा" का उपयोग करता हूं। –

संबंधित मुद्दे