2017-11-11 51 views
2

我剛剛發現this post並想知道如何在Haskell中做類似的事情。在下面,我只是簡化了我有困難的部分:高效地訪問像素

我有一個包含大量2D座標的列表。對於simplicitys的緣故,讓我們假設該列表包含Int座標是所有範圍內的0 - 1023

points :: [(Int,Int)] -- long list of points 

的目標現在具有圖像(讓我們說img :: [[Int]]其中img和每個條目其長度爲1024),其中(img!!i)!!j(i,j)points(它將被映射到一些灰度值)的出現次數。

我試了一下,到目前爲止:

  1. 如果我只是用遍歷points並試圖incerment一些二維數組的進入i,j,約撿一些入門i,j,並增加了部分的必要途徑這一方面非常麻煩,可能效率不高,另一方面使用!!容易出現index too large錯誤。
  2. 效率稍高一點的方法:對於座標(i,j)的每個對,使用partition來篩選出(i,j)條目並對它們進行計數,並將其餘列表傳遞給下一對座標。這樣我們得到一個(i,j, count)的列表,我們只需要將count插入每個像素i,j一次,但在我看來,這仍然不是很優雅。

所以,你可以建議如何做到這一點的更高效,更優雅功能任何方式解決?

這只是一個示例性問題,因爲我經常遇到類似的問題,只發現不滿意的解決方案。


編輯:由於這裏要求是這種代碼的一個例子:


main = putStrLn "before:" >> print myImg >> putStrLn "after:" >> print myImg2 
     >> putStrLn "output of our \"image\":" >> print outImg 

n :: Int 
n = 4 

-- example for "increment" 
myImg = [[n..n+3]|n<-[1,5..16]] :: [[Int]] 
myImg2 = increment myImg 2 3 10000 

-- example for our application 
zeroImg = [[0,0,0,0]|_<-[0,0,0,0]] 
outImg = foldl (\img (i,j) -> increment img i j 1) zeroImg points 

-- our "data" (here im just filling this with arbitrary numbers) 
points = [(i `mod` n,j `mod` n)|i <-[1..14],j<-[i..77+i]]  


-- not very elegant code 
increment :: [[Int]] -> Int -> Int -> Int -> [[Int]] 
increment img i j v = a ++ [x ++ [y + v] ++ z] ++ c -- increments the "pixel" (i,j) by v 
    where  
    a = take i img   
    b = img !! i 
    c = drop (i+1) img 
    x = take j b 
    y = b !! j 
    z = drop (j+1) b 

Try it online!

+0

有些語言可以互換使用這些術語,這取決於您所說的語言,但這不是重點。我認爲我們是否使用列表並不重要,難點在於訪問和使用索引更改某些內容。如果你堅持你可以用例如來自'Codec.Picture'的'Image',但我的問題基本保持不變。 – flawr

+1

您有關*更有效和優雅的功能方式*的問題。所以,我寫了什麼使用列表這不是有效的方式。關於*優雅的功能方式*,也許如果你添加你的解決方案,它可以幫助我們在這裏瞭解你的問題? – freestyle

+0

通常,解決Haskell上的這些問題並不意味着什麼,因爲您是從對命令式代碼很方便的數據開始的。但是你應該從那些方便功能方式的數據開始。例如,您可以通過添加兩個圖像來更改此問題。其中一個將是你的原始圖像,第二個將是一個「從你的觀點創建」的圖像。 – freestyle

回答

2

您可以使用,作爲一種變型,Data.Array

import Data.Array 

main = do 
    putStrLn "before:" >> print myArr 
    putStrLn "after:" >> print myArr2 
    putStrLn "output of our \"image\":" >> print outArr 

n :: Int 
n = 4 

-- example for "increment" 
myArr = listArray ((0,0), (n-1,n-1)) [1..] 
myArr2 = accum (+) myArr [((2, 3), 1000)] 

-- example for our application 
outArr = accumArray (+) 0 ((0,0), (n-1,n-1)) [ (p, 1) | p <- points ] 

-- our "data" (here im just filling this with arbitrary numbers) 
points = [(i `mod` n,j `mod` n)|i <-[1..14],j<-[i..77+i]] 

使用repavector

import Control.Monad 
import Data.Array.Repa 
import qualified Data.Vector.Generic as V 
import qualified Data.Vector.Generic.Mutable as MV 

main = putStrLn "output of our \"image\":" >> print outArr 

n :: Int 
n = 1024 

-- example for our application 
outArr :: Array U DIM2 Int 
outArr = fromUnboxed (Z :. n :. n) $ V.create $ do 
    v <- MV.new (n * n) 
    MV.set v 0 
    forM_ points $ \(i, j) -> do 
     let idx = i * n + j 
     MV.modify v (+1) idx 
    pure v 

-- our "data" (here im just filling this with arbitrary numbers) 
points = [(i `mod` n,j `mod` n)|i <-[1..14],j<-[i..77+i]]