2011-10-11 33 views
6

Lấy cảm hứng từ Comparing list lengthdanh sách So sánh chiều dài với mũi tên

Nếu tôi muốn tìm danh sách dài nhất trong một danh sách liệt kê, cách đơn giản nhất có lẽ là:

longestList :: [[a]] -> [a] 
longestList = maximumBy (comparing length) 

Một cách hiệu quả hơn sẽ để tính toán trước độ dài:

longest :: [[a]] -> [a] 
longest xss = snd $ maximumBy (comparing fst) [(length xs, xs) | xs <- xss] 

Bây giờ, tôi muốn tiến thêm một bước nữa. Nó có thể không hiệu quả hơn đối với các trường hợp thông thường, nhưng bạn có thể giải quyết này bằng cách sử dụng các mũi tên không? Ý tưởng của tôi là cơ bản, bước qua tất cả các danh sách cùng một lúc, và tiếp tục bước cho đến khi bạn đã overstepped chiều dài của tất cả các danh sách ngoại trừ dài nhất.

longest [[1],[1],[1..2^1000],[1],[1]] 

Trong forgoing (rất giả tạo) Ví dụ, bạn sẽ chỉ phải mất hai bước qua từng danh sách để xác định rằng danh sách [1..2^1000] là dài nhất, mà không bao giờ cần phải xác định toàn bộ chiều dài của danh sách nói . Tôi có đúng là điều này có thể được thực hiện với các mũi tên không? Nếu có thì làm sao? Nếu không, thì tại sao không, và cách tiếp cận này có thể được thực hiện như thế nào?

+1

Tôi không thấy bất kỳ kết nối nào với mũi tên. – luqui

+0

@luqui một phần của Wikibook Haskell trên [Sử dụng mũi tên] (http://en.wikibooks.org/wiki/Haskell/Understanding_arrows#Using_arrows) dường như nêu rõ rằng các mũi tên hữu ích cho việc phân tích cú pháp theo cách tương tự với của tôi giải pháp đề xuất cho vấn đề này (xem phần tử đầu tiên của mỗi danh sách, sau đó là phần thứ hai, vv) [Hướng dẫn mũi tên của Stephen] (http: //en.wikibooks.org/wiki/Haskell/StephensArrowTutorial) mang đến cho tôi cảm giác giống nhau: các mũi tên đó có thể được sử dụng để tìm hiểu các danh sách này và lưu trữ thông tin khi chúng đi. –

+0

Tôi đã chấp nhận câu trả lời, nhưng nếu ai đó có thể đưa ra câu trả lời bằng mũi tên, hoặc giải thích kỹ lưỡng tại sao mũi tên không thích hợp, thì tôi chắc chắn sẽ chấp nhận câu trả lời đó. –

Trả lời

2

Suy nghĩ về điều này một số chi tiết, có một giải pháp đơn giản hơn nhiều mang đến các đặc tính hiệu suất giống nhau. Chúng tôi chỉ có thể sử dụng maximumBy với chức năng so sánh độ dài lười biếng:

compareLength [] [] = EQ 
compareLength _ [] = GT 
compareLength [] _ = LT 
compareLength (_:xs) (_:ys) = compareLength xs ys 

longest = maximumBy compareLength 
+0

+1 Điều đó thực sự rất thanh lịch. Tuy nhiên, nếu tôi không nhầm, nó sẽ duyệt lại danh sách mỗi lần so sánh 2 danh sách để xem danh sách dài hơn. –

+0

@DanBurton: Có, nhưng chỉ đến chừng nào ngắn hơn trong hai danh sách. Vì vậy, nó chỉ là một câu hỏi mà phương pháp tiếp cận có các yếu tố liên tục cao nhất, mà tôi phải thừa nhận tôi đã không được thử nghiệm. – hammar

+0

Hoặc bạn có thể sử dụng loại dữ liệu đại số cho số nhị phân để biểu thị độ dài của danh sách. Bằng cách này bạn chỉ nhận được một yếu tố logarit trong độ dài của một danh sách để so sánh độ dài của hai danh sách và vẫn nhận được ít nhất một mức độ lười biếng. –

4

OK, như tôi đã viết câu hỏi, nó chợt nhận ra tôi một cách đơn giản để thực hiện điều này (không có mũi tên, boo!)

longest [] = error "it's ambiguous" 
longest [xs] = xs 
longest xss = longest . filter (not . null) . map (drop 1) $ xss 

Trừ này có một vấn đề ... nó giảm phần đầu tiên của danh sách và không phục hồi nó!

> take 3 $ longest [[1],[1],[1..2^1000],[1]] 
[2,3,4] 

nhu cầu kế toán hơn: P

longest xs = longest' $ map (\x -> (x,x)) xs 

longest' [] = error "it's ambiguous" 
longest' [xs] = fst xs 
longest' xss = longest . filter (not . null . snd) . map (sndMap (drop 1)) $ xss 

sndMap f (x,y) = (x, f y) 

Bây giờ nó hoạt động.

> take 3 $ longest [[1],[1],[1..2^1000],[1]] 
[1,2,3] 

Nhưng không có mũi tên. :(Nếu nó có thể được thực hiện với mũi tên, sau đó hy vọng câu trả lời này có thể cung cấp cho bạn một nơi nào đó để bắt đầu.

+0

Ngoài ra, 'errror" nó mơ hồ "' là một cách khá crappy để xử lý danh sách có cùng độ dài. Meh. Câu hỏi này được thiết kế đặc biệt cho trường hợp bạn có nhiều danh sách ngắn và một danh sách ngắn. –

3

Đây là việc thực hiện đơn giản nhất mà tôi có thể nghĩ đến. Không mũi tên tham gia, mặc dù.

tôi giữ một danh sách các trong đó phần tử đầu tiên là danh sách gốc, và phần tử thứ hai là đuôi còn lại, nếu chúng ta chỉ còn lại một danh sách, thì chúng ta sẽ lấy đuôi của tất cả các danh sách còn lại, lọc ra những người trống. Nếu một số vẫn còn, hãy tiếp tục. Nếu không, chúng có cùng độ dài và chúng ta tùy ý chọn cái đầu tiên.

longest [] = error "longest: empty list" 
longest xss = go [(xs, xs) | xs <- xss] 
    where go [(xs, _)] = xs 
     go xss | null xss' = fst . head $ xss 
       | otherwise = go xss' 
       where xss' = [(xs, ys) | (xs, (_:ys)) <- xss] 
+0

Tôi _could_ thay đổi dòng thứ hai thành 'longest xss = go $ map (id &&& id) xss', nhưng tôi đoán đó không phải là cách sử dụng mũi tên mà bạn đang nghĩ đến :) – hammar

Các vấn đề liên quan