How do I generate a 2D Array with values, each with neighbours of different, non-repeating values? - arrays

I have a square 2D Array, which I wish to fill with values between 1 to 4.
For this to be correct, the neighbours of any of the values inside the array would need to look like this, as an example:
x 2 x
3 1 1
x 4 x
The x values are irrelevant to the middle value 1. As we can see, the neighbours of middle value 1 do not appear more than once, aside from itself
An incorrect value's neighbours would look like this:
x 2 x
3 1 2
x 4 x
One of the neighbours of middle value 1 appear more than once (the value of 2 appears twice), and we don't want this.
I have made a LUA solution for this problem, but it is very slow, as all it does is add 2 rules to the generation and runs through all combinations until it finds a valid one.
The rules being:
Corner neighbours (in our case the xs) cannot have the same value as the middle value
The next value OVER the relevant neighbours cannot have the same value as the middle value.
Explanation for rule 2:
y y y y
y 1 y x
y y y y
The x in this instance cannot have the value of 1, this applies for every vertical and horizontal direction (up-down-left-right)
EDIT: I now know I can just repeat a tileable pattern, but this is not what I wanted, as I do not want a clear repetition to be observable

You can simply repeat a pattern to get the desired array.
Row 1: 1 2 3 4 1 2 3... repeated for the required number of columns
Row 2: 3 4 1 2 3 4 1... repeated similarly
Row 3: Same as row 2
Row 4: Same as row 1
Row 5: Start repeating pattern from row 1
...continued for the required number of rows.
Here's an example for a 6x6 grid:
1 2 3 4 1 2
3 4 1 2 3 4
3 4 1 2 3 4
1 2 3 4 1 2
1 2 3 4 1 2
3 4 1 2 3 4
This is guaranteed to follow both rules, since:
The diagonal for a value of x here will always be 5 - x, and x != (5 - x) for x in [1,2,3,4].
The next over value for 1 will always be 3 and vice versa (in any direction), and same for 2 and 4.
Edit: In your comment, you've mentioned that you needed the array to be more "varied". Any form of randomness would mean that we can't use any patterns. In that case, your current solution can not be improved, since you can't use any pattern for optimisation.

You can use a Block that if repeated any number of times in any direction does not Break the neigbour-constraint. One such Block (I'm sure there are others, but this is the most trivial I think) would be:
1 1 2 2
3 3 4 4
2 2 1 1
4 4 3 3
You can repeat this Block any number of times in any direction and every cell will always have unique neighbors.
For example, if you need a 6x8-array just repeat the Block once to the right and down, and then slice according to the size you want:
1 1 2 2 1 1
3 3 4 4 3 3
2 2 1 1 2 2
4 4 3 3 4 4
1 1 2 2 1 1
3 3 4 4 3 3
2 2 1 1 2 2
4 4 3 3 4 4
Fun Fact: On further inspection one might recognize, that Abhinav Mathur and I came up with a somewhat similar solution. If you rotate my Block and swap the 2 with the 3, the pattern is the same. But his formulation with repeating rows instead of the whole block is probably easier to implement in most cases.

I write this as a second answer as there is a new requirement: Don't use any repeating pattern!
TLDR
Just fill the array row for row, left to right. With following constraint:
You want to fill the value x, then you only have to consider the values in the colored cells.
If the green cell is filled, then there is only one possibility for x (the one value that is not in either the green or red cells)
If the green cell is empty (you are at the left border). Then there are two options (one of the values that is not in the red cells). But the value that you choose has to be one of the values in the blue cells too (this is always possible) or otherwise it will be impossible to fill the value y later! If the blue cells aren't filled (right border) you can just ignore this secondary constraint.
Explanation
You can separate this into two independent problems. Think of your array like a chessboard and solve the numbers in the light and dark fields separately as they don't care about each other (light and dark don't share any neighbors because their neighbors are always of the opposite color respectively).
So you split your chessboard in light and dark (just to better understand, you don't have to actually separate the arrays).
Then you solve them separately with some simple constraints. The value (green) is not allowed to be equal to one of the values two cells apart (red):
Just fill the values row by row from left to right. You can only actually choose a value at the left border as the rest will be constrained by the other three values above. At this left border you have to be careful. The chosen value in the green cell has to be the same as one of the values in the blue cells. Otherwise the next cell (red) will be impossible!
Just do this for the light and dark cells and then put them back together:
This should be relatively easy to implement and really fast, as it is not brute-forcing anything but directly constructing a valid solution. When saying choose a number or fill values I mean to just get the possible values and choose one at random.
You can try yourself in excel too, it's like a really boring sudoku as there is actually not much to choose, it is really constrained :).

Related

MATLAB - extract array values based on conditions

I have 4x4 matrix A
[1 2 3 4;
2 2 2 3;
5 5 5 5;
4 4 4 4]
I know how to locate all values less than 4. A<4. But I'm not sure how to write an 'if' statement for; three or more values, all which are less than 4, contained in the same row. For instance; see above A(1,:) and A(2,:) satisfies my conditions.
You can basically do A<4 to know which ones are smaller. If you want to know which rows contain N values smaller than 4 then you can do
rows=find(sum(A<4,2)>=3)
This basically does:
find smaller than 4
Count how many of them in each row (sum(_,2))
find if they are 3 or more
give the row index of those find()

Change axis in histogram Matlab

I have an array A defined as
A = [1 0 1 1 0 1 2 3 1 2 3 ];
I want to make histogram of this array. I have tried with
hist(A)
But the problem is it shows value 1 is 5 times, 2 is 2 times and so on. But I want like it as at position 1 value 1, at 2 value is 0 , at 3 value is 1 and so on.
hist counts the number of occurances of each value in the input* and uses those for the height of the bars. This is why the output is what you mention. What you want, however, is just bar because your input A already is a histogram.
bar(A);
%// Add some histogram labels
xlabel('Index')
ylabel('Frequency')
*This isn't technically correct since it depends on the bins, but for this specific input it is the case.

Count based on column and row

I can't seem to find something quite like this problem...
I have an array table where each row contains a random assortment of numbers 1-N
On another sheet, I have a table with column and row headers numbered 1-N
I want to count how many rows in the array contain both the column and row headers for a given cell in the table. Since countifs only reference the current cell in the specified array, they don't seem to be working in this scenario.
Example array:
A B C D
1 3 5 7
1 2 3 4
2 3 4 5
2 4 6 8
...
Table results (symmetrical about the diagonal):
A B C D E F
. 1 2 3 4 5 ...
1 - 1 2 1 1
2 1 - 2 2 1
3 2 2 - 2 2
4 1 2 2 - 1
5 1 1 2 1 -
Would using nested countifs work?
I don't agree with your results corresponding to 4/2, which surely should be 3, not 2, but this formula, based on the array table being in Sheet1 A1:D4 and the results table being in Sheet2 A1:F6, placed in cell B2 of the latter, should work:
=IF($A2=B$1,"-",SUMPRODUCT(N(MMULT(N(COUNTIF(OFFSET(Sheet1!$A$1:$D$1,ROW(Sheet1!$A$1:$D$4)-MIN(ROW(Sheet1!$A$1:$D$4)),),CHOOSE({1,2},B$1,$A2))>0),{1;1})=2)))
Copy across and down as required.
Note: If your actual table is in fact much larger than that given, it will probably be worth adding a simple clause into the above to the effect that the results for approximately half of the cells are obtained from their symmetrical counterparts, rather than via calculation of this construction, thus saving resource.
Regards

Given 2 positions (x1,y1) and (x2,y2) print the sum of all elements within the area of rectangle in O(1) time

A 2D matrix is given to you. Now user will give 2 positions (x1,y1) and (x2,y2),
which is basically the upper left and lower right coordinate of a rectangle formed within the matrix.
You have to print sum of all the elements within the area of rectangle in O(1) running time.
Now you can do any pre computation with the matrix.
But when it is done you should answer all your queries in constant time.
Example : consider this 2D matrix
1 3 5 1 8
8 3 5 3 7
6 3 9 6 0
Now consider 2 points given by user (0, 2) and (2, 4).
Your solution should print: 44.
i.e., the enclosed area is
5 1 8
5 3 7
9 6 0
Since your question seems to be related to homeworks, i am just posting a clue... It is a formula that may inspire you :
What does this sum of terms represent ?
Rewrite your problem using mathematical tools, indexes like i and j ...
maybe this can also help:
courtosy of: http://www.techiedelight.com/calculate-sum-elements-sub-matrix-constant-time/

Calling multiple values from data frame by row and column in R

I'm working in R and I'd like to call a selection of values from a data frame by their column and row indices. However doing this yields a matrix rather than an array. I shall demonstrate:
Given the data.frame:
a = data.frame( a = array(c(1,2,3,4,5,6,7,8,9), c(3,3)) )
(for those of you who don't want to plug it in, it looks like this)
a.1 a.2 a.3
1 1 4 7
2 2 5 8
3 3 6 9
And lets say I have two arrays pointing to the values I'd like to grab
grab_row = c(3,1,2)
grab_col = c(1,2,1)
Now I'd expect this to be the code I want...
a[ grab_row, grab_col ]
To get these results...
[1] 3 4 2
But that comes out as a 3x3 matrix, which makes enough sense in and of itself
a.1 a.2 a.1.1
3 3 6 3
1 1 4 1
2 2 5 2
Alright, I also see my answer is in the diagonal of the 3x3 matrix... but I'd really rather stick to an array as the output.
Any thoughts? Danka.
Passing the row and column indices in as a two-column matrix (here constructed using cbind()) will get you the elements you were expecting:
a[cbind(grab_row, grab_col)]
[1] 3 4 2
This form of indexing is documented in ?"[":
Matrices and array:
[...snip...]
A third form of indexing is via a numeric matrix with the one
column for each dimension: each row of the index matrix then
selects a single element of the array, and the result is a vector.
Try this:
> mapply(function(i,j)a[i,j], grab_row, grab_col)
[1] 3 4 2
Works for both dataframes and matrices.

Resources