2014-04-15 27 views
0

我想以逐行方式打印三元組列表。該列表包含三元組,每個三元組的第一個元素應放置在作爲三元組的第二個和第三個元素給出的座標中。網格從(0,0)座標開始。下面 是一個2x2格例如:從三元組列表中打印2D網格

generateGrid [('a',0,0),('b',0,2),('c',1,1), ('d',2,2)] 
-> a - b 
    - c - 
    - - d 

我不得不產生這種功能的方法,但我不能把一切都放在代碼。 我試圖找到三元組中的最大數字,並通過增加的值創建網格。這樣我可以從(0,0)cooradinate開始。然後,我想遍歷所有三元組,並將第一個元素放入相關座標中。 我怎樣才能做到這一點?

下面是我的代碼:

gridMax ((p1, p2, p3):xs) = max (maximum(secList ((p1, p2, p3):xs))) (maximum(thirdList ((p1, p2, p3):xs))) 

secList [] = [] 
secList ((p1, p2, p3):xs) = [p2] ++ secList xs 

thirdList [] = [] 
thirdList ((p1, p2, p3):xs) = [p3] ++ thirdList xs 

這種方式,我發現,這意味着我應該創建一個(最大+ 1)×電網的最大(MAX + 1)電網從(0,0) 。我無法獲得代碼的其餘部分。

+0

您如何向我們展示您設法在代碼中放置了什麼? - 至於算法...我會做一個排序組交錯空間接近。不需要知道三元組的總數。 – leftaroundabout

+0

我編輯了我的問題並分享了我的一些工作。 – nudaStck

+0

我並不重複,因爲你的問題至少是連貫的,但有一天有人問了一個類似的問題,我提供了一些提示。 http://stackoverflow.com/questions/22997734/print-function-drawf-from-a-list-of-tuples/22998207 – bheklilr

回答

1

由於Haskell的懶惰,我們可以假設我們有一個無限的網格,所以我們可以根據參數中給出的座標一個接一個地在這個網格上設置單元格,並在此記錄結果網格的大小處理。當我們完成時,我們可以從該無限網格中獲取結果網格。

下面是這種想法的實現:

setVal :: Int -> a -> [a] -> [a] 
setVal idx val lst = h ++ (val : tail t) 
    where (h, t) = splitAt idx lst 

setCell :: (Char, Int, Int) -> [[Char]] -> [[Char]] 
setCell (c, x, y) grid = setVal x xl grid 
    where xl = setVal y c $ grid !! x 

generateGrid :: [(Char, Int, Int)] -> [[Char]] 
generateGrid cs = take (mx+1) $ map (take (my+1)) grid 
    where (mx, my, grid) = foldr step (0, 0, g) cs 
      g = repeat $ repeat '-' 
      step [email protected](c, x, y) (mx, my, g) = 
      let g' = setCell co g 
       mx' = max x mx 
       my' = max y my 
      in 
       (mx', my', g') 

難道這樣的測試:

*Main> let cs = [('a',0,0),('b',0,2),('c',1,1), ('d',2,2)] :: [(Char, Int, Int)] 
*Main> putStr $ unlines $ generateGrid cs 
a-b 
-c- 
--d 
+0

非常感謝。它幫助我瞭解其他相關步驟。 – nudaStck

+0

@nudaStck你可以試試看看會發生什麼:-) –

+0

:) Ofcourse,我試過了,但它給出了類型錯誤:類型:[(Char,Integer,Integer)]不匹配:[(Char,Int,Int )]。 – nudaStck

0

只是爲了好玩,這裏是哈斯克爾的一行:

generateGrid :: [((Int, Int), Char)] -> String 
generateGrid xs = 
    unlines $ map (map snd) $ groupBy ((==) `on` fst . fst) $ assocs $ accumArray (const id) '-' ((0,0), (maximum $ map (fst . fst) xs, maximum $ map (snd . fst) xs)) xs 

讓我們解碼一下這裏發生了什麼:

generateGrid :: [((Int, Int), Char)] -> String 
generateGrid xs = 
    unlines .       
    map (map snd) . 
    groupBy ((==) `on` fst . fst) . 
    assocs . 
    accumArray (const id) 
      '-' 
      ((0,0), (maximum $ map (fst . fst) xs, maximum $ map (snd . fst) xs))  
    $ xs 

我們要做的第一件事就是使用accumArray :: (e -> a -> e) -> e -> (i, i) -> [(i, a)] -> Array i e創建一個數組。它需要一個'默認'元素 - 在這裏'-'由於顯而易見的原因;一個組合函數,在這裏const id - 它只返回第二個元素,它將是從列表中抽取的元素;範圍從(0,0)開始並以最大值結束;最後是xs輸入列表,它是與值Char相關聯的鍵(Int, Int)的列表。

這整個要點是用((x,y),'-')「填充」空的空間。 accumArray是一個非常簡單的方法。

然後我們用assocs從列表中取出列表。

下一個函數將獲取關聯列表並將它們分組到子列表中 - 每個子列表包含一行。

現在我們有一個行列表 - 我們不再對指數感興趣,所以map (map snd)擺脫它們。最後,unlines將行組合成由換行符分隔的單個字符串。