Printing a 2d array in haskell - arrays

I'm messing around with printing a random 2d array of Ints, in this simple image format (PPM)
0 1 0 0 1
1 0 0 1 0
0 1 1 0 0
0 1 1 1 0
0 0 0 1 0
Below is my code, which works, but seems like way too much code for such a simple operation. Is there a better way to do this?
import System.Random
import Data.Array.IArray
main = do
g <- newStdGen
let img = listArray ((0,0),(5,5)) ( myRands g ) :: Array (Int,Int) Int
putStrLn $ printArray img
myRands :: RandomGen g => g -> [Int]
myRands g = randomRs (0,1) g
make2dRange :: Int -> Int -> Int -> Int -> [(Int,Int)]
make2dRange x1 y1 x2 y2 = range ((x1,y1),(x2,y2))
printArray :: ( Array (Int,Int) Int ) -> String
printArray arr = unlines rows
where rows = map (unwords . map (show . (!) arr)) rowIndices
rowIndices = map ( \y -> make2dRange 0 y 5 y ) [0..5]
Other than the obvious, of course (array dimensions are hardcoded, for example)

I would use list comprehensions to manipulate the indices.
printArray arr =
unlines [unwords [show (arr ! (x, y)) | x <- [0..5]] | y <- [0..5]]

per: http://lambda.haskell.org/platform/doc/current/packages/split-0.2.2/doc/html/Data-List-Split.html#v%3achunksOf
chunksOf :: Int -> [e] -> [[e]]
chunksOf n splits a list into length-n pieces. The last piece will be shorter if n does not evenly divide the length of the list. If n <= 0, chunksOf n l returns an infinite list of empty lists.
using chunksOf my implementation would be..
printArray arr = mapM_ (putStrLn . unwords) $ map (map show) $ chunksOf 5 arr
usage:
Prelude System.Random Data.List Data.List.Split> printArray [0..25]
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
25

Related

error: sub2ind: all subscripts must be of the same size using Octave 4.2.2

I'm getting an error: sub2ind: all subscripts must be of the same size. The line that seems to be the issue is idx = sub2ind ([n m], r, c)
If I try and make the array certain sizes I get that error (see some of the values below that cause the issue)
%values that cause the error
array_rows=3; %3,3,7,7
array_cols=6; %6,5,3,5
How can I get it to work with these values and others that cause this error (I'm sure there are more values that cause this error)?
The Original question: was answered and solved by Andy here
See code below:
function r = rndtrip (n, m, v)
rv = #(x) x - 2 * (v - 1);
r = [v * ones(1,rv(m)-1) v:n-v+1 (n-v+1)*ones(1,rv(m)-2)];
if (rv(m) > 1)
r = [r n-v+1:-1:v+1];
endif
endfunction
function idx = ring (n, m , v)
if (2*(v-1) > min (n, m))
r = [];
else
r = rndtrip (n, m, v);
c = circshift (rndtrip (m, n, v)(:), - n + 2 * v - 1).';
idx = sub2ind ([n m], r, c)
endif
endfunction
# your array
array_rows=3; %3,3,7,7
array_cols=6; %6,5,3,5
I_orig = reshape (1:array_rows*array_cols, array_cols, array_rows).' %reshape array %I_orig = reshape (1:30, 5, 6).'
[rw_orig col_orig]=size(I_orig);
I_new=I_orig; %where the new rotated values will be stored
min_rows_cols=min(rw_orig,col_orig); %get min number of row - columns used to calc number of rings
r=(-1).^(1:ceil(min_rows_cols/2)) % (toggles beween -1 1)
%r = [1 -1] %used to have ring rotate CCW or CW can be done manually
for k = 1:numel(r)
idx = ring (rows(I_new), columns(I_new), k);
I_new(idx) = I_new(circshift(idx(:), r(k)));
endfor
I_new
I_orig =
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
r =
-1 1
idx =
1 4 7 10 13 16 17 18 15 12 9 6 3 2
error: sub2ind: all subscripts must be of the same size
error: called from ring at line 16 column 9
Values that Work with the Code run on TIO
Values that don't work with the Code run on TIO
Ps: I'm using Ubuntu 18.04 Octave 4.2.2

Reduce 3d to 2d array by using an index vector for one dimension

I have a M x N x O matrix and I would like to reduce it to a MxN matrix in MATLAB using a vector b of size M that contains the index of the element in the third dimension that is to be kept.
What it does then is build a 2d array with its entries selected from various pages of the original 3d array.
I have this loop but I am interested in a loopless solution.
for i = 1:M
for j = 1:N
tmp(i, j) = P(i, j, b(i));
end
end
The easiest way may just be to remove the j loop in your code:
for ii = 1:M
tmp(ii, :) = P(ii, :, b(ii));
end
But for the sake of comparison, here's a solution without a loop.
Given a 3d array P:
M = 7;
N = 5;
O = 6;
P = ones(M, N, O) .* permute(1:O, [3 1 2]);
(in this case I've used a 3d array where each element is equal to its O index)
and b, of size Mx1 with values from 1..O:
b = randi(O, M, 1)
you can construct the subscripts of all of the elements of P(:,:,1) and use b to select which plane to use:
[rr, cc] = ndgrid(1:M, 1:N);
inds = sub2ind(size(P), rr(:), cc(:), b(rr(:)));
tmp = reshape(P(inds), M, N)
For:
b.' = 5 4 1 5 3 1 3
we get:
tmp =
5 5 5 5 5
4 4 4 4 4
1 1 1 1 1
5 5 5 5 5
3 3 3 3 3
1 1 1 1 1
3 3 3 3 3
The elements of each row corresponds to the element in b as expected.

List of n first Neighbors from a 3d Array R

Lets say we have a 3d array:
my.array <- array(1:27, dim=c(3,3,3))
I would like to create a list of the n first neighbors.
Example: Lets get my.array[2,2,2]=14, so the first neighbors of 14 is:
list[14] = [1 to 27] - 14
I also would like to do the same for second, third, n closest neighbors using R, C or Matlab.
Thanks
Based on the comments, I assume you are defining "first nearest neighbor" as all cells with a euclidean distance of 1 or less (excluding self), "second nearest neighbors" as those with 2 or less, etc. Your assertion in a comment in #evan058's answer that "for (1,1,1) the first level neighbors is 2,4,5,10,11,13", I'm actually interpreting this to include the immediate diagonals (with a distance of 1.414) but not further diagonals (in your example, 14 would be a further diagonal with a distance of 1.732).
This function accepts either a pre-defined array (ary) or the dimensions to make one (dims).
nearestNeighbors(dims = c(3,3,3), elem = c(1,1,1), dist = 1)
# dim1 dim2 dim3
# [1,] 2 1 1
# [2,] 1 2 1
# [3,] 1 1 2
nearestNeighbors(dims = c(3,3,3), elem = c(1,1,1), dist = 1,
return_indices = FALSE)
# [1] 2 4 10
nearestNeighbors(dims = c(3,3,3), elem = c(1,1,1), dist = 2,
return_indices = FALSE)
# [1] 2 3 4 5 7 10 11 13 14 19
nearestNeighbors(ary = array(27:1, dim = c(3,3,3)), elem = c(1,1,1), dist = 2)
# dim1 dim2 dim3
# [1,] 2 1 1
# [2,] 3 1 1
# [3,] 1 2 1
# [4,] 2 2 1
# [5,] 1 3 1
# [6,] 1 1 2
# [7,] 2 1 2
# [8,] 1 2 2
# [9,] 2 2 2
# [10,] 1 1 3
nearestNeighbors(ary = array(27:1, dim = c(3,3,3)), elem = c(1,1,1), dist = 2,
return_indices = FALSE)
# [1] 26 25 24 23 21 18 17 15 14 9
The function:
#' Find nearest neighbors.
#'
#' #param ary array
#' #param elem integer vector indicating the indices on array from
#' which all nearest neighbors will be found; must be the same
#' length as \code{dims} (or \code{dim(ary)}). Only one of
#' \code{ary} and \code{dim} needs to be provided.
#' #param dist numeric, the max distance from \code{elem}, not
#' including the 'self' point.
#' #param dims integer vector indicating the dimensions of the array.
#' Only one of \code{ary} and \code{dim} needs to be provided.
#' #param return_indices logical, whether to return a matrix of
#' indices (as many columns as dimensions) or the values from
#' \code{ary} of the nearest neighbors
#' #return either matrix of indices (one column per dimension) if
#' \code{return_indices == TRUE}, or the appropriate values in
#' \code{ary} otherwise.
nearestNeighbors <- function(ary, elem, dist, dims, return_indices = TRUE) {
if (missing(dims)) dims <- dim(ary)
tmpary <- array(1:prod(dims), dim = dims)
if (missing(ary)) ary <- tmpary
if (length(elem) != length(dims))
stop("'elem'' needs to have the same dimensions as 'ary'")
# work on a subset of the whole matrix
usedims <- mapply(function(el, d) {
seq(max(1, el - dist), min(d, el + dist))
}, elem, dims, SIMPLIFY=FALSE)
df <- as.matrix(do.call('expand.grid', usedims))
# now, df is only as big as we need to possibly satisfy `dist`
ndist <- sqrt(apply(df, 1, function(x) sum((x - elem)^2)))
ret <- df[which(ndist > 0 & ndist <= dist),,drop = FALSE]
if (return_indices) {
return(ret)
} else {
return(ary[ret])
}
}
Edit: changed the code for a "slight" speed improvement: using a 256x256x256 array and a distance of 2 previously took ~90 seconds on my machine. Now it takes less than 1 second. Even a distance of 5 (same array) takes less than a second. Not fully tested, please verify it is correct.
Edit: Removed the extra { on the fifty line of the function.
I think something along these lines will do the trick:
nClosest <- function(pts, pt, n)
{
# Get the target value
val <- pts[pt[1], pt[2], pt[3]]
# Turn the matrix into a DF
ptsDF <- adply(pts, 1:3)
# Create Dist column for distance to val
ptsDF$Dist <- abs(ptsDF$V1 - val)
# Order by the distance to val
ptsDF <- ptsDF[with(ptsDF, order(Dist)),]
# Split into groups:
sp <- split(ptsDF, ptsDF$Dist)
# Get max index
topInd = min(n+1, length(sp))
# Agg the split dfs into a single df
rbind.fill(sp[2:topInd])
}
Output:
> nClosest(my.array, c(1,2,2), 3)
X1 X2 X3 V1 Dist
1 3 1 2 12 1
2 2 2 2 14 1
3 2 1 2 11 2
4 3 2 2 15 2
5 1 1 2 10 3
6 1 3 2 16 3

Matlab reshape horizontal cat

Hi I want to reshape a matrix but the reshape command doesn't order the elements the way I want it.
I have matrix with elements:
A B
C D
E F
G H
I K
L M
and want to reshape it to:
A B E F I K
C D G H L M
So I know how many rows I want to have (in this case 2) and all "groups" of 2 rows should get appended horizontally. Can this be done without a for loop?
You can do it with two reshape and one permute. Let n denote the number of rows per group:
y = reshape(permute(reshape(x.',size(x,2),n,[]),[2 1 3]),n,[]);
Example with 3 columns, n=2:
>> x = [1 2 3; 4 5 6; 7 8 9; 10 11 12]
x =
1 2 3
4 5 6
7 8 9
10 11 12
>> y = reshape(permute(reshape(x.',size(x,2),n,[]),[2 1 3]),n,[])
y =
1 2 3 7 8 9
4 5 6 10 11 12
Cell array approach -
mat1 = rand(6,2) %// Input matrix
nrows = 3; %// Number of rows in the output
[m,n] = size(mat1);
%// Create a cell array each cell of which is a (nrows x n) block from the input
cell_array1 = mat2cell(mat1,nrows.*ones(1,m/nrows),n);
%// Horizontally concatenate the double arrays obtained from each cell
out = horzcat(cell_array1{:})
Output on code run -
mat1 =
0.5133 0.2916
0.6188 0.6829
0.5651 0.2413
0.2083 0.7860
0.8576 0.3032
0.1489 0.4494
out =
0.5133 0.2916 0.5651 0.2413 0.8576 0.3032
0.6188 0.6829 0.2083 0.7860 0.1489 0.4494

loop through two variable in Haskell

What is the haskell way to do this?
for (int i = 0 ; i < 1000 ; i++)
for (int j = 0 ; j < 1000 ; j++)
ret = foo(i , j ) #I need the return value.
More background:
I am solving euler problem 27 , and I have got:
value a b =
let l = length $ takeWhile (isPrime) $ map (\n->n^2 + a * n + b) [0..]
in (l, a ,b)
The next step is to get a list of tuple by looping through all the possible a and b and then do the following processing:
foldl (\(max,v) (n,a,b)-> if n > max then (n , a * b) else (max ,v) ) (0,0) tuple_list
but I have no idea how to loop through two variables ..Thanks.
Use a nested list comprehension. Here 'foo' is '(,)'':
[ (i,j) | i <- [0 .. 999], j <- [0 .. 999] ]
Or laid out to make the nesting clearer:
[ foo i j
| i <- [0 .. 999]
, j <- [0 .. 999]
]
As well as dons' answer, you can use the list monad:
do
i <- [0 .. 999]
j <- [0 .. 999]
return (foo i j)
You can also do this nicely using Control.Applicative
module Main where
import Control.Applicative
main :: IO ()
main = mapM_ putStrLn (foo <$> [0..3] <*> [0..3])
foo :: Int -> Int -> String
foo a b = "foo " ++ show a ++ " " ++ show b
Example run:
C:\programming>ghc --make Main.hs
[1 of 1] Compiling Main ( Main.hs, Main.o )
Linking Main.exe ...
C:\programming>main
foo 0 0
foo 0 1
foo 0 2
foo 0 3
foo 1 0
foo 1 1
foo 1 2
foo 1 3
foo 2 0
foo 2 1
foo 2 2
foo 2 3
foo 3 0
foo 3 1
foo 3 2
foo 3 3

Resources