2009-05-30 5 views
4

죄송합니다. 아직 FP를 얻지 못했습니다. 일련의 줄을 일련의 줄로 나누고 싶습니다. 단락 분할로 빈 줄을 가정하면 다음과 같이 파이썬에서 그럴 수 있습니다.기능 단락

def get_paraghraps(lines): 
    paragraphs = [] 
    paragraph = [] 
    for line in lines: 
     if line == "": # I know it could also be "if line:" 
      paragraphs.append(paragraph) 
      paragraph = [] 
     else: 
      paragraph.append(line) 
    return paragraphs 

얼랑 (Erlang)이나 하스켈 (Haskell)에서 어떻게 하죠?

답변

4

저는 하스켈 프로그래머입니다. (그리고 5 년 전 배운 작은 하스켈입니다.)하지만 처음에는 누산기 ("현재 단락")를 사용하여 함수의 자연 번역을 작성했습니다.) (난 그냥 명확성을 위해, 종류를 추가했습니다) 주위에 전달되는 :

type Line = String 
type Para = [Line] 

-- Takes a list of lines, and returns a list of paragraphs 
paragraphs :: [Line] -> [Para] 
paragraphs ls = paragraphs2 ls [] 

-- Helper function: takes a list of lines, and the "current paragraph" 
paragraphs2 :: [Line] -> Para -> [Para] 
paragraphs2 [] para = [para] 
paragraphs2 ("":ls) para = para : (paragraphs2 ls []) 
paragraphs2 (l:ls) para = paragraphs2 ls (para++[l]) 

이 작동 :

*Main> paragraphs ["Line 1", "Line 2", "", "Line 3", "Line 4"] 
[["Line 1","Line 2"],["Line 3","Line 4"]] 

그래서 그 해결책입니다. 그러나, 하스켈 경험 groupBy라고이 : 하나 개 관련 기능 등의 작업을 수행하는 라이브러리 함수는 거의 항상 있다는 것을 시사하고 거의 작동합니다

paragraphs3 :: [Line] -> [Para] 
paragraphs3 ls = groupBy (\x y -> y /= "") ls 

*Main> paragraphs3 ["Line 1", "Line 2", "", "Line 3", "Line 4"] 
[["Line 1","Line 2"],["","Line 3","Line 4"]] 

아차. 우리가 정말 필요한 것은 "splitBy"및 it's not in the libraries이지만, 우리는 나쁜 사람에게 자신을 필터링 할 수 있습니다

paragraphs4 :: [Line] -> [Para] 
paragraphs4 ls = map (filter (/= "")) (groupBy (\x y -> y /= "") ls) 

또는, 당신은 멋진하려는 경우, 당신은 인수 제거 할 수와 그것을 할 무의미한 방법 :

paragraphs5 = map (filter (/= "")) . groupBy (\x y -> y /= "") 

내가 더 짧은 방법이 확신 해요.:-)

편집 : ephemient(not . null)(/= "") 청소기보다라고 지적한다. 그래서 우리는

paragraphs = map (filter $ not . null) . groupBy (const $ not . null) 

반복 (not . null) 강한 표시이다 쓸 수 우리 기능으로,이 아래 질문에 대해 답 지적으로 Data.List.Split module은 무엇이며이 밖으로 정말해야 추상입니다.

+0

당신은 그것에 대한 참조가 있습니까? 하스켈 98 도서관 보고서 (http://www.cs.auckland.ac.nz/references/haskell/haskell-library-1.4-html/list.html) *는 평등 술어이지만, groupBy 함수. groupBy의 타입 시그니처에는 "Eq"제약이 없으므로 임의의 (전이?) 술어 함수로 작업해야한다고 제안합니다 ...이 방법으로 사용하는 것이 일반적입니다 : http : //www.haskell .org/haskellwiki/List_function_suggestions # Generalize_groupBy_and_friends – ShreevatsaR

+2

'not '를 사용하고 싶습니다. '(== "")'을 사용하여 더 이상 무의미한'paragraphs = map (filter $ not. null)으로 이끌 것입니다. groupBy (const $ not. null)' – ephemient

3

재귀 적으로 생각해보십시오.

get_paragraphs []  paras para = paras ++ [para] 
get_paragraphs ("":ls) paras para = get_paragraphs ls (paras ++ [para]) [] 
get_paragraphs (l:ls) paras para = get_paragraphs ls paras (para ++ [l]) 
+1

오 마이! 그것 [Paras] (http://bulbapedia.bulbagarden.net/wiki/Paras) 내가 볼 수 있습니까? –

4

저는 하스켈도 배우려고합니다. 이 질문에 대한 해결책은 될 수있다 :

paragraphs :: [String] -> [[String]] 
paragraphs [] = [] 
paragraphs lines = p : (paragraphs rest) 
    where (p, rest) = span (/= "") (dropWhile (== "") lines) 

내가 Data.List에서 기능을 사용하고 있습니다 곳. 내가 사용하고있는 것들은 Prelude에서 이미 구할 수 있지만, 링크에서 그들의 문서를 찾을 수 있습니다.

아이디어는 span (/= "")을 사용하여 첫 번째 단락을 찾는 것입니다. 단락과 뒤에 나오는 줄을 반환합니다. 그런 다음 우리가 rest이라고 부르는 작은 줄의 목록에서 반복합니다.

첫 번째 단락을 분리하기 전에 dropWhile (== "")을 사용하여 모든 빈 줄을 삭제합니다. 단락을 구분하는 빈 줄을 먹는 것이 중요합니다. 내 첫 번째 시도는이이었다

paragraphs :: [String] -> [[String]] 
paragraphs [] = [] 
paragraphs lines = p : (paragraphs $ tail rest) 
    where (p, rest) = span (/= "") lines 

하지만 우리는 rest부터 마지막 ​​단락에 도달했을 때이 빈 문자열 다음입니다 실패

 
*Main> paragraphs ["foo", "bar", "", "hehe", "", "bla", "bla"] 
[["foo","bar"],["hehe"],["bla","bla"]*** Exception: Prelude.tail: empty list 

빈 줄을 삭제하는 것은이 문제를 해결, 그리고 그것은 또한 코드를 치료한다 단락 구분 기호로 빈 줄 수에 관계없이 사용자로 기대됩니다.

+1

'null'은 빈리스트와 문자열과 동등 함을 테스트하는 것보다 훨씬 효율적이고 명확합니다. 'span (/ = "")'=>'break null','dropWhile (== "")'=>'dropWhile null' 모두 가독성을 향상시킵니다. – ephemient

+0

예 및 아니오 - 문자열 목록에서 빈 문자열을 검색 할 때 ""을 (를) 검색하는 것이 더 읽기 쉽다고 생각합니다. 적어도 나 같은 초보자를위한 :-) –

3

줄을 그룹화하려는 경우 groupBy에서 Data.List까지는 좋은 후보로 보입니다. 사용자 정의 함수를 사용하여 어떤 행이 "동등"한지 판별하므로 동일한 단락의 행을 "동등하게"제공 할 수 있습니다. 예를 들어 : inpara는 인접한 두 라인을 비교할 수 있습니다 더 복잡한 논리가 groupBy에 의해 주어진 프레임 워크에 적합하지 않기 때문에

import Data.List(groupBy) 

inpara :: String -> String -> Bool 
inpara _ "" = False 
inpara _ _ = True 

paragraphs :: [String] -> [[String]] 
paragraphs = groupBy inpara 

이, 몇 가지 제한 사항이 있습니다. 더 많은 요소 솔루션은 더 유연합니다. 기본 재귀를 사용하여 작성할 수

paragraphs [] = [] 
paragraphs as = para : paragraphs (dropWhile null reminder) 
    where (para, reminder) = span (not . null) as 
          -- splits list at the first empty line 

span 제공된 기능이 거짓 (첫 번째 빈 라인)이되는 지점 목록을 분리, dropWhile 제공된 기능이 참 (선행 빈 라인)되는 주요한 요소를 제거 .

4

가장 깨끗한 해결책은 split 패키지에서 적절한 것을 사용하는 것입니다.

먼저 설치해야하지만, 그 다음에 Data.List.Split.splitWhen null이 작업을 완벽하게 수행해야합니다.

0

결코 늦지 않는 것이 좋습니다.

import Data.List.Split (splitOn) 

paragraphs :: String -> [[String]] 
paragraphs s = filter (not . null) $ map words $ splitOn "\n\n" s 

paragraphs "a\nb\n\nc\nd"    == [["a", "b"], ["c", "d"]] 
paragraphs "\n\na\nb\n\n\nc\nd\n\n\n" == [["a", "b"], ["c", "d"]] 
paragraphs "\n\na\nb\n\n \n c\nd\n\n\n" == [["a", "b"], ["c", "d"]]