问题
I'm trying to make a function that will take a list of lists of Int
s as an input, and adds +1 every time it runs into a number bigger or equal to 10. I added -20 on each side so xc
can start at 0.
Example what should happen after the function runs into first '10':
[[-20,-20, 0, 0, 0, 0, 0, 0, 0,-20,-20],
[-20,-20, 0,10, 1, 0, 0, 0, 0,-20,-20],
[-20,-20, 1, 1, 1, 0,10, 0, 0,-20,-20],
[-20,-20, 0, 0, 0,10, 0, 0, 0,-20,-20],
[-20,-20, 0, 0, 0, 0, 0, 0,10,-20,-20],
[-20,-20,10,10,10, 0, 0, 0, 0,-20,-20],
[-20,-20,10, 0,10, 0, 0, 0, 0,-20,-20],
[-20,-20,10,10,10, 0, 0, 0, 0,-20,-20]]
SampleInput = [[-20,-20, 0, 0, 0, 0, 0, 0, 0,-20,-20],
[-20,-20, 0,10, 0, 0, 0, 0, 0,-20,-20],
[-20,-20, 0, 0, 0, 0,10, 0, 0,-20,-20],
[-20,-20, 0, 0, 0,10, 0, 0, 0,-20,-20],
[-20,-20, 0, 0, 0, 0, 0, 0,10,-20,-20],
[-20,-20,10,10,10, 0, 0, 0, 0,-20,-20],
[-20,-20,10, 0,10, 0, 0, 0, 0,-20,-20],
[-20,-20,10,10,10, 0, 0, 0, 0,-20,-20]]
adder::[[Int]] -> [[Int]]
adder ((xa:xb:xc:xd:xe):(ya:yb:yc:yd:ye))
| xc >= 10 = adder ((xb:xc:(xd+1):xe):((yb+1):(yc+1):(yd+1):ye))
| otherwise = adder ((xb:xc:xd:xe):(yb:yc:yd:ye))
I also dont know how to apply xa : adder
... which we could do fairly easily if it was a single list. Any ideas how to fix this code?
Also, you can replace -20 with anything up to 10 if needed, its just for orientation, since I plan to delete these -20s after the function is applied to the list.
I will want to run function second time on a reversed list, you can see why if you imagine minesweeper where 10s are mines
回答1:
I see how you arrived at this idea. In a sense, you are creating a gigantic pattern and move it along the minefield. It can work. But it is not an easy way.
adder :: [[Int]] -> [[Int]]
adder [ ] = [ ]
adder [x] = [x]
adder t@[ [_, _], [_, _] ] = t
adder (u@[_, _]: v@[_, _]: us) = u: v: adder us
adder t = afterPass !! 0: adder (afterPass !! 1: us)
where
t' = applyHalfStencil t
( (x: xs)
: (y: ys)
: us
) = t'
xys = [xs, ys]
afterPass = [x: adder xys !! 0, y: adder xys !! 1]
applyHalfStencil
s@( (xa: xb: xc: xs)
: (ya: yb: yc: ys)
: us
)
| xb > 9 =
( (xa : xb : xc + 1: xs)
: (ya + 1: yb + 1: yc + 1: ys)
: us
)
| otherwise = s
Of course, you have to also pad your field with -20
s above and below. By the way, one layer of
-20
is enough. Sample:
sampleInput :: [[Int]]
sampleInput = [ [-20 , -20 , -20 , -20 , -20 , -20]
, [-20 , 10 , 0 , 0 , 0 , -20]
, [-20 , 0 , 10 , 10 , 10 , -20]
, [-20 , 0 , 10 , 0 , 10 , -20]
, [-20 , 0 , 10 , 10 , 10 , -20]
, [-20 , -20 , -20 , -20 , -20 , -20] ]
While we are at it, nothing stops us from applying the whole stencil at once, not just the lower right half of it.
adder :: [[Int]] -> [[Int]]
adder [ ] = [ ]
adder [x] = [x]
adder [x, y] = [x, y]
adder t@[ [_, _], _, _ ] = t
adder (u@[_, _]: v: w: us) = u: v: w: adder us
adder t = afterPass !! 0: adder (afterPass !! 1: afterPass !! 2: us)
where
t' = applyStencil t
( (x: xs)
: (y: ys)
: (z: zs)
: us
) = t'
xyzs = [xs, ys, zs]
afterPass = [x: adder xyzs !! 0, y: adder xyzs !! 1, z: adder xyzs !! 2]
applyStencil
s@( (xa: xb: xc: xs)
: (ya: yb: yc: ys)
: (za: zb: zc: zs)
: us
)
| yb > 9 =
( (xa + 1: xb + 1: xc + 1: xs)
: (ya + 1: yb : yc + 1: ys)
: (za + 1: zb + 1: zc + 1: zs)
: us
)
| otherwise = s
So, here we are, another solution. It is probably more efficient. It is also good that you put creative force into the problem.
To the future reader, for context: this question and answer continue the line of inquiry started in our previous cooperation with Jakub.
回答2:
I think it's rather easy, as long as the data structure stays as [[Int]]
. See the below example:
addIf10 :: Int -> Int
addIf10 x = if x >= 10 then x + 1 else x
-- The first map "unpacks" the list to form an [Int]
-- Second map runs the addIf10 function on the [Int]
adder :: [[Int]] -> [[Int]]
adder = map (map addIf10)
来源:https://stackoverflow.com/questions/58827023/how-to-make-my-function-move-through-two-lists-at-once