Multidimensional Array - set to table data from array - arrays

I have problem with Multidimensional Array. I created calculate between two types of data from one table.
Example data from table BT_MATRYCA.
And I division data from TYP: VAL_A since COL1 to COL17 by value from SUMA_RAZEM from row with TYP: VAL_B.
Command "put d_st[i,j] =;" puts good value but I need create table with this calculate (Multidimensional, with X and Y). How I can do?
data BT_MATRYCA;
infile DATALINES dsd missover;
input NAME $ TYP $ COL1 COL2 COL3 COL4 COL5 COL6 COL7 COL8 COL9 COL10 COL11 COL12 COL13 COL14 COL15 COL16 COL17 SUMA_RAZEM;
CARDS;
A1, VAL_A, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 500
A1, VAL_B, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 600
B1, VAL_A, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 13, 14, 15, 16, 16, 20, 550
B1, VAL_B, 1, 20, 3, 20, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 800
C1, VAL_A, 20, 2, 3, 4, 5, 6, 7, 8, 9, 10, 30, 12, 13, 14, 15, 16, 17, 900
C1, VAL_B, 1, 2, 3, 20, 5, 6, 7, 8, 02, 10, 11, 12, 30, 14, 15, 16, 17, 780
;run;
data t3;
array m[6,18] _temporary_;
array n[6,18] _temporary_;
array d_st[6,18] _temporary_;
call missing(of d_st[*]);
if _n_ = 1 then do;
do i = 1 by 1 until(z1);
set BT_MATRYCA (where=(TYP = 'VAL_A')) end = z1;
array c[18] COL1--SUMA_RAZEM;
do j = 1 to 18;
m[i, j] = c[j];
end;
end;
do i = 1 by 1 until(z2);
set BT_MATRYCA (where=(TYP = 'VAL_B')) end = z2;
array v[18] COL1--SUMA_RAZEM;
do j = 1 to 18;
n[i,j] = v[j];
end;
end;
end;
do i = 1 to 6;
do j = 1 to 18;
IF m[i,18] ne 0 then
d_st[i,j] = coalesce((n[i,j] / m[i,18]),0);
ELSE
d_st[i,j] = 0;
end;
end;
do i = 1 to 6;
do j = 1 to 18;
put d_st[i,j] =;
end;
end;
stop;
run;
`

It isn't particularly clear what you're asking, but it sounds as though you want something like this:
data t3 wide(keep = x1-x6) long(keep = x y z);
array m[6,18] _temporary_;
array n[6,18] _temporary_;
array d_st[6,18] _temporary_;
array _x[6] x1-x6;
put d_st[1,1]=;
if _n_ = 1 then do;
do i = 1 by 1 until(z1);
set BT_MATRYCA (where=(TYP = 'VAL_A')) end = z1;
array c[18] COL1--SUMA_RAZEM;
do j = 1 to 18;
m[i, j] = c[j];
end;
end;
do i = 1 by 1 until(z2);
set BT_MATRYCA (where=(TYP = 'VAL_B')) end = z2;
array v[18] COL1--SUMA_RAZEM;
do j = 1 to 18;
n[i,j] = v[j];
end;
end;
end;
do i = 1 to 6;
do j = 1 to 18;
IF m[i,18] ne 0 then
d_st[i,j] = coalesce((n[i,j] / m[i,18]),0);
ELSE
d_st[i,j] = 0;
end;
end;
/* Note switching of inner and outer loops*/
do j = 1 to 18;
do i = 1 to 6;
_x[i] = d_st[i,j];
x = i;
y = j;
z = d_st[i,j];
output long;
end;
output wide;
end;
stop;
run;

Related

ruby - rotate Matrix anti-clockwise by n position

Given a 2D matrix:
matrix = [
[ 1, 2, 3, 4 ],
[ 5, 6, 7, 8 ],
[ 9, 10, 11, 12 ],
[ 13, 14, 15, 16 ]
]
How can we rotate the matrix anti-clockwise so that values are pushed like this?
matrix = [
[ 2, 3, 4, 8 ]
[ 1, 7, 11, 12 ]
[ 5, 6, 10, 16 ]
[ 9, 13, 14, 15 ]
]
Note
This question is not a duplicate of this & this because what I'm trying to achieve is by rotating the values in anti-clockwise fashion.
My current implementation & Problem
My current implementation only prints out the values in anti-clockwise fashion, but it does not rotate the values.
layers = [_rows, _cols].min / 2
r1, r2, c3, c4 = 0, _rows, _cols, _cols
new_matrix = Array.new(_rows + 1) { Array.new(_cols + 1) }
(0..layers).each do |layer|
row_top_left, row_bottom_left, col_top_right, col_bottom_right = r1, r2, c3, c4
result = []
while row_top_left < row_bottom_left
result << matrix[row_top_left][layer]
row_top_left += 1
end
row_bottom_left = layer
while row_bottom_left < col_bottom_right
result << matrix[row_top_left][row_bottom_left]
row_bottom_left += 1
end
temp_col_bottom_right = col_bottom_right
temp_col_top_right = layer
while col_bottom_right > temp_col_top_right
result << matrix[col_bottom_right][temp_col_bottom_right]
col_bottom_right -= 1
end
# p row_top_left
tmp_row_top_left = layer
while col_top_right > tmp_row_top_left
result << matrix[tmp_row_top_left][col_top_right]
col_top_right -= 1
end
p result.cycle
r1 += 1
r2 -= 1
c3 -= 1
c4 -= 1
update v0.1
The key idea is that the matrix needs to be rotated in the correct way. For example, let's say our matrix requires 2 rotation. Therefore:
matrix_rotation(
matrix.length - 1, # rows
matrix[0].length - 1, # columns
2, # Nom. of rotation
matrix # The matrix
)
matrix = [
# Original Iter: 1 Iter: 2
[ 1, 2, 3, 4 ], # [ 2, 3, 4, 8 ] # [ 3, 4, 8, 12 ]
[ 5, 6, 7, 8 ], # [ 1, 7, 11, 12 ] # [ 2, 11, 10, 16 ]
[ 9, 10, 11, 12 ], # [ 5, 6, 10, 16 ] # [ 1, 7, 6, 15 ]
[ 13, 14, 15, 16 ] # [ 9, 13, 14, 15 ] # [ 5, 9, 13, 14 ]
]
Update v0.2
The dimension of the array is denoted: NxM where N and M can be any numbers, even or odd. For example 5x4, 4,4, 4x8 etc..
There is no such thing as "empty squares".
TL:DR
If you want to jump straight to the solution code, jump to the bottom section of this answer.
Explanation
You need to break down the problem and solve each one independently.
Problems
Get the number of layers
Loop in reverse spiral form to just get the expected values
Shift them based on the rotation parameter given
Let us walk through each point separately:
Get the number of layers
You need a way to get the number of layers. The below matrix has 2 layers. How?
given a matrix:
matrix layers
--------------------------------
| 1, 2, 3, 4 | 0 0 0 0 |
| 5, 6, 7, 8 | 0 1 1 0 |
| 9, 10, 11, 12 | 0 1 1 0 |
| 13, 14, 15, 16 | 0 0 0 0 |
--------------------------------
To find the number of layers, simply do:
[rows, cols].min / 2
Thus the first problem is done.
Loop in reverse spiral form to just get the expected values
This part requires a lot of thinking. Let us visualise:
matrix layers
--------------------------------
| 1, 2, 3, 4 | ↓ ← ← ↰ | 0 0 0 0 |
| 5, 6, 7, 8 | ↓ 1 1 ↑ | 0 ↓ ↰ 0 |
| 9, 10, 11, 12 | ↓ 1 1 ↑ | 0 ↳ → 0 |
| 13, 14, 15, 16 | ↳ → → → | 0 0 0 0 |
--------------------------------
This is achievable. We will have 4 for loops. Each loop will take care of:
left (top to bottom)
bottom (left to right)
right (bottom to top)
top (right to left)
Before I get into the loops, we need some container to store our values in spiral form.
Let us have a temp array to store the values:
# this array will get us the output of borders of the layer
row = []
For the sake of explanation, let us only work on the outer most layer. (i.e. 0th layer:
1st Loop (Left: top to bottom)
# this loop will output the top-left side of the matrix
# ==============================
# ↓ [ 1, 2, 3, 4 ]
# ↓ [ 5, 6, 7, 8 ]
# ↓ [ 9, 10, 11, 12 ]
# ↓ [ 13, 14, 15, 16 ]
# Output: [[1, 5, 9], [6] ]
# ==============================
(0...rows - 1 - layer).each do |i|
row << matrix[i][layer]
end
Note: 0 means the 0th layer.
2nd Loop (Bottom: Left to Right)
# this loop will output the bottom side of the matrix
# ==============================
# ↓ [ 1, 2, 3, 4 ]
# ↓ [ 5, 6, 7, 8 ]
# ↓ [ 9, 10, 11, 12 ]
# ↓ [ 13, 14, 15, 16 ]
# ↪ → → → →
# Output: [[1, 5, 9, 13, 14, 15], [6, 10]]
# ==============================
(0...cols - 1 - layer).each do |i|
row << matrix[rows - 1 - layer][i]
end
3rd Loop (Right: Bottom to Top)
# this loop will output the right side of the matrix
# ==============================
# ↓ [ 1, 2, 3, 4 ] ↑
# ↓ [ 5, 6, 7, 8 ] ↑
# ↓ [ 9, 10, 11, 12 ] ↑
# [ 13, 14, 15, 16 ] ↑
# ↪ → → → → ⤻
# Output: [[1, 5, 9, 13, 14, 15, 16, 12, 8], [6, 10, 11]]
# ==============================
(rows - 1 - layer).step(0 + 1, -1).each do |i|
row << matrix[i][cols - 1 - layer]
end
4th Loop (Top: Right to Left)
# this loop will output the top side of the matrix
# ==============================
# ← ← ← ← ↰
# ↓ [ 1, 2, 3, 4 ] ↑
# ↓ [ 5, 6, 7, 8 ] ↑
# ↓ [ 9, 10, 11, 12 ] ↑
# [ 13, 14, 15, 16 ] ↑
# ↪ → → → → ⤻
# Output: [[1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2], [6, 10, 11, 7]]
# ==============================
(cols - 1 - layer).step(0 + 1, -1).each do |i|
row << matrix[layer][i]
end
Shift them based on the rotation parameter given
So now at this point, we have the values in the spiral form. But the most important aspect of this problem lies in this section. How does one shift the values? Funnily enough, we will use modulo.
The modulo will do the main thing here. It will allow us to shift values based on the rotate. But also give us the correct index in the array to start the shift. For example, if we want to rotate 2 times: 2 % 12 = 2 for the outer most layer.
# row = [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2]
shift = rotate % row.size
# if we negate shift variable, we can get correct index
# i.e. row[-2] = 3
idx = -shift
Before we shift values, let us create another matrix which will contain the correct values:
# let us create a new matrix
result = (1..( rows * cols )).each_slice(rows).to_a
We will loop again in the same manner, but get the values from the idx in row. For example:
(0...rows - 1 - 0).each do |i|
result[i][layer] = row[idx]
idx += 1
idx %= row.size
end
(0...cols - 1 - 0).each do |i|
result[rows - 1 - 0][i] = row[idx]
idx += 1
idx %= row.size
end
(rows - 1 - 0).step(0 + 1, -1).each do |i|
result[i][cols - 1 - 0] = row[idx]
idx += 1
idx %= row.size
end
(cols - 1 - 0).step(0 + 1, -1).each do |i|
result[0][i] = row[idx]
idx += 1
idx %= row.size
end
Note: 0 is the 0th layer (for the sake of explanation)
Solution
matrix_4_x_4 = (1..16).each_slice(4).to_a
matrix_8_x_8 = (1..64).each_slice(8).to_a
def matrix_rotation(*args)
# let us extract rows & cols from our matrix. We also need to know how
# times to rotate.
rows, cols, rotate, matrix = args
# to find out how many layers our matrix have, simply get the min of the two (rows, cols)
# and divide it
layers, str_cols = [rows, cols].min / 2, ""
# needed to beatify our console output in table format
cols.times do str_cols << "%5s " end
# we will work on a temporary array
temp_rows = []
# so the first task is to loop n times, where n is the number of layers
(0...layers).each do |layer|
# this array will get us the output of borders of the layer
row = []
# this loop will output the top-left side of the matrix
# ==============================
# ↓ [ 1, 2, 3, 4 ]
# ↓ [ 5, 6, 7, 8 ]
# ↓ [ 9, 10, 11, 12 ]
# ↓ [ 13, 14, 15, 16 ]
# Output: [[1, 5, 9], [6] ]
# ==============================
(layer...rows - 1 - layer).each do |i|
row << matrix[i][layer]
end
# this loop will output the bottom side of the matrix
# ==============================
# ↓ [ 1, 2, 3, 4 ]
# ↓ [ 5, 6, 7, 8 ]
# ↓ [ 9, 10, 11, 12 ]
# ↓ [ 13, 14, 15, 16 ]
# ↪ → → → →
# Output: [[1, 5, 9, 13, 14, 15], [6, 10]]
# ==============================
(layer...cols - 1 - layer).each do |i|
row << matrix[rows - 1 - layer][i]
end
# this loop will output the right side of the matrix
# ==============================
# ↓ [ 1, 2, 3, 4 ] ↑
# ↓ [ 5, 6, 7, 8 ] ↑
# ↓ [ 9, 10, 11, 12 ] ↑
# [ 13, 14, 15, 16 ] ↑
# ↪ → → → → ⤻
# Output: [[1, 5, 9, 13, 14, 15, 16, 12, 8], [6, 10, 11]]
# ==============================
(rows - 1 - layer).step(layer + 1, -1).each do |i|
row << matrix[i][cols - 1 - layer]
end
# this loop will output the top side of the matrix
# ==============================
# ← ← ← ← ↰
# ↓ [ 1, 2, 3, 4 ] ↑
# ↓ [ 5, 6, 7, 8 ] ↑
# ↓ [ 9, 10, 11, 12 ] ↑
# [ 13, 14, 15, 16 ] ↑
# ↪ → → → → ⤻
# Output: [[1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2], [6, 10, 11, 7]]
# ==============================
(cols - 1 - layer).step(layer + 1, -1).each do |i|
row << matrix[layer][i]
end
temp_rows << row
end
# let us create a new matrix
result = (1..( rows * cols )).each_slice(rows).to_a
# we're going to loop in the same manner as before
(0...layers).each do |layer|
# based on current layer, get the values around that layer
row = temp_rows[layer]
# !important: the modulo will do the main thing here:
# It will allow us to shift values based on the rotate. But also
# gives us the correct index in the array to start the shift.
# For example, if we want to rotate 2 times: 2 % 12 = 2 for the outer most layer
shift = rotate % row.size
# when whe negate the shift value, we will get the correct index from the end of the array.
# row = [1, 5, 9, 13, 14, 15, 16, 12, 8, 4, 3, 2]
# So -2 in row[-2] for the outer layer is 3. We increment idx, then row[-1] is 2 etc..
idx = -shift
(layer...rows - 1 - layer).each do |i|
result[i][layer] = row[idx]
idx += 1
idx %= row.size
end
(layer...cols - 1 - layer).each do |i|
result[rows - 1 - layer][i] = row[idx]
idx += 1
idx %= row.size
end
(rows - 1 - layer).step(layer + 1, -1).each do |i|
result[i][cols - 1 - layer] = row[idx]
idx += 1
idx %= row.size
end
(cols - 1 - layer).step(layer + 1, -1).each do |i|
result[layer][i] = row[idx]
idx += 1
idx %= row.size
end
end
result.each do |row| printf("#{str_cols}\n", *row) end
end
matrix_rotation(
matrix_8_x_8.size,
matrix_8_x_8.first.size,
2,
matrix_8_x_8
)
Code
def nxt(rows, cols, row, col)
case row
when rows[:first]
col == cols[:last] ? [row+1, col] : [row, col+1]
when rows[:last]
col == cols[:first] ? [row-1, col] : [row, col-1]
else
col == cols[:last] ? [row+1, col] : [row-1, col]
end
end
def rotate_array_times(matrix, n)
arr = matrix.dup.map(&:dup)
nrows, ncols = arr.size, arr.first.size
0.upto([nrows, ncols].min/2-1) do |m|
rows = { first: m, last: nrows-m-1 }
cols = { first: m, last: ncols-m-1 }
rect_size = 2 * (nrows + ncols) - 8*m - 4
rotations = n % rect_size
row = col = rrow = rcol = m
rotations.times { rrow, rcol = nxt(rows, cols, rrow, rcol) }
rect_size.times do
arr[row][col] = matrix[rrow][rcol]
row, col = nxt(rows, cols, row, col)
rrow, rcol = nxt(rows, cols, rrow, rcol)
end
end
arr
end
Examples
matrix = [
[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16]
]
(1..3).each { |n| p rotate_array_times(matrix, n) }
[[2, 3, 4, 8],
[1, 7, 11, 12],
[5, 6, 10, 16],
[9, 13, 14, 15]]
[[3, 4, 8, 12],
[2, 11, 10, 16],
[1, 7, 6, 15],
[5, 9, 13, 14]]
[[4, 8, 12, 16],
[3, 10, 6, 15],
[2, 11, 7, 14],
[1, 5, 9, 13]]
matrix = (1..24).each_slice(4).to_a
#=> [[ 1, 2, 3, 4],
# [ 5, 6, 7, 8],
# [ 9, 10, 11, 12],
# [13, 14, 15, 16],
# [17, 18, 19, 20],
# [21, 22, 23, 24]]
(1..3).each { |n| p rotate_array_times(matrix, n) }
#=> [[ 2, 3, 4, 8],
# [ 1, 7, 11, 12],
# [ 5, 6, 15, 16],
# [ 9, 10, 19, 20],
# [13, 14, 18, 24],
# [17, 21, 22, 23]]
# [[ 3, 4, 8, 12],
# [ 2, 11, 15, 16],
# [ 1, 7, 19, 20],
# [ 5, 6, 18, 24],
# [ 9, 10, 14, 23],
# [13, 17, 21, 22]]
# [[ 4, 8, 12, 16],
# [ 3, 15, 19, 20],
# [ 2, 11, 18, 24],
# [ 1, 7, 14, 23],
# [ 5, 6, 10, 22],
# [ 9, 13, 17, 21]]
matrix = (1..48).each_slice(8).to_a
#=> [[ 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, 26, 27, 28, 29, 30, 31, 32],
# [33, 34, 35, 36, 37, 38, 39, 40],
# [41, 42, 43, 44, 45, 46, 47, 48]]
(1..3).each { |n| p rotate_array_times(matrix, n) }
[[ 2, 3, 4, 5, 6, 7, 8, 16],
[ 1, 11, 12, 13, 14, 15, 23, 24],
[ 9, 10, 20, 21, 22, 30, 31, 32],
[17, 18, 19, 27, 28, 29, 39, 40],
[25, 26, 34, 35, 36, 37, 38, 48],
[33, 41, 42, 43, 44, 45, 46, 47]]
[[ 3, 4, 5, 6, 7, 8, 16, 24],
[ 2, 12, 13, 14, 15, 23, 31, 32],
[ 1, 11, 21, 22, 30, 29, 39, 40],
[ 9, 10, 20, 19, 27, 28, 38, 48],
[17, 18, 26, 34, 35, 36, 37, 47],
[25, 33, 41, 42, 43, 44, 45, 46]]
[[ 4, 5, 6, 7, 8, 16, 24, 32],
[ 3, 13, 14, 15, 23, 31, 39, 40],
[ 2, 12, 22, 30, 29, 28, 38, 48],
[ 1, 11, 21, 20, 19, 27, 37, 47],
[ 9, 10, 18, 26, 34, 35, 36, 46],
[17, 25, 33, 41, 42, 43, 44, 45]]
Explanation
nxt
Given row and column indices row and col, nxt(rows, cols, row, col) returns the indices [next_row, next_col] of the "next" element on the perimeter of a subarray that is to replace the element (also on the perimeter) at indices [row, col] in a single iteration. The subarray is given by the hashes rows and cols which each have keys :first and :last.
Let's consider an an array arr with 4 elements (rows), each element (row) having 6 values (columns). Then
nrows, ncols = arr.size, arr.first.size
#=> [4, 6]
If m = 0
rows = { first: m, last: nrows-m-1 }
#=> {:first=>0, :last=>3}
cols = { first: m, last: ncols-m-1 }
#=> {:first=>0, :last=>5}
It is seen that rows and cols describes the "perimeter" of he array matrix. We can see how nxt works as follows.
first_row, first_col = rows[:first], cols[:first]
row, col = first_row, first_col
print "[#{row}, #{col}]"
loop do
next_row, next_col = nxt(rows, cols, row, col)
print "->[#{next_row}, #{next_col}]"
row, col = next_row, next_col
(puts; break) if [row, col] == [first_row, first_col]
end
[0, 0]->[0, 1]->[0, 2]->[0, 3]->[0, 4]->[0, 5]->[1, 5]->[2, 5]->[3, 5]->
[3, 4]->[3, 3]->[3, 2]->[3, 1]->[3, 0]->[2, 0]->[1, 0]->[0, 0]
If m = 1, the above calculation yields
[1, 1]->[1, 2]->[1, 3]->[1, 4]->[2, 4]->[2, 3]->[2, 2]->[2, 1]->[1, 1]
rotate_array_times
This method constructs a deep copy of matrix, arrr, whose elements are rotated in the prescribed matter n times and then returns the resulting array.
To speed calculations, n is replaced by a modulus of itself. For a 4x4 array, for example, after 12 iterations the perimeter of the array would be back to its original value. Therefore, it is sufficient to perform n % 12 rotations.
matrix contains n = [matrix.size, matrix.first.size].min subarrays whose perimeters are to be rotated. The top-left corner of each subarray is given by the coordinate [m,m], where m = 0..n-1.
For the subarray specified by m the first step is to determine the location of the element of matrix that is to replace the element of arr at [m,m]. That is done in the line
rotations.times { rrow, rcol = nxt(rows, cols, rrow, rcol) }
("rrow" and "rcol" for "replacement row" and "replacement col", respectively). At this time the element of arr at location row #=> m, col #=> m is to be replaced the element of matrix at the location given by rrow and rcol. The following operations then performed as many times as there are elements in the perimeter of the subarray which are to be rotated:
arr[row][col] = matrix[rrow][rcol]
row, col = nxt(rows, cols, row, col)
rrow, rcol = nxt(rows, cols, rrow, rcol)
Tweaking efficiency
A modest improvement in efficiency could be achieved by replacing the line
rotations.times { rrow, rcol = nxt(rows, cols, rrow, rcol) }
with
rrow, rcol = first_replacement_loc(rows, cols, rotations)
and adding the following method.
def first_replacement_loc(rows, cols, rotations)
ncm1 = cols[:last]-cols[:first]
nrm1 = rows[:last]-rows[:first]
return [rows[:first], cols[:first]+rotations] if rotations <= ncm1
rotations -= ncm1
return [rows[:first]+rotations, cols[:last]] if rotations <= nrm1
rotations -= nrm1
return [rows[:last], cols[:last]-rotations] if rotations <= ncm1
rotations -= ncm1
[rows[:last]-rotations, cols[:first]]
end
This is another implementation (I didn't make a method, just the logic that needs to be improved).
array = (1..24).each_slice(6).to_a
array.each { |e| p e }
puts
n = 4 # sub matrix rows
m = 6 # sub matrix cols
x = 0 # x row origin (corner) of the rotation
y = 0 # y col origin (corner) of the rotation
rotations = 2 # negative is ccw, positive is cw
raise "Sub matrix too small, must be 2x2 at least" if m < 2 || n < 2
# to add: check if the submatrix is inside the matrix, given the origin x, y
y_size = array.size
x_size = array.size
idx_map = Array.new(n){ [] }
m.times.map { |mm| n.times.map { |nn| idx_map[nn][mm] = [nn + x, mm + y] } }
before = [(idx_map.map(&:shift)).concat(idx_map.pop).concat(idx_map.map(&:pop).reverse).concat(idx_map.shift.reverse)].flatten(1)
after = before.rotate(rotations)
tmp = array.map(&:dup)
before.size.times.map { |idx| array[before[idx][0]][before[idx][1]] = tmp[after[idx][0]][after[idx][1]]}
array.each { |e| p e }
#=> [1, 2, 3, 4, 5, 6]
#=> [7, 8, 9, 10, 11, 12]
#=> [13, 14, 15, 16, 17, 18]
#=> [19, 20, 21, 22, 23, 24]
#=>
#=> [13, 7, 1, 2, 3, 4]
#=> [19, 8, 9, 10, 11, 5]
#=> [20, 14, 15, 16, 17, 6]
#=> [21, 22, 23, 24, 18, 12]
You can also rotate a 3x3 sub-matrix starting in (1, 1), so, for example n = 3, m = 3, x = 1, y = 1 and rotations = -1:
#=> [1, 2, 3, 4, 5, 6]
#=> [7, 9, 10, 16, 11, 12]
#=> [13, 8, 15, 22, 17, 18]
#=> [19, 14, 20, 21, 23, 24]
I thought it would be interesting to benchmark my code against #Humbledore's. (#iGian: I can add your code to the benchmark if you can edit your answer to wrap it in a method with arguments matrix and nbr_rotations).
def nxt(rows, cols, row, col)
case row
when rows[:first]
col == cols[:last] ? [row+1, col] : [row, col+1]
when rows[:last]
col == cols[:first] ? [row-1, col] : [row, col-1]
else
col == cols[:last] ? [row+1, col] : [row-1, col]
end
end
def cary1(matrix, n)
arr = matrix.dup.map(&:dup)
nrows, ncols = arr.size, arr.first.size
0.upto([nrows, ncols].min/2-1) do |m|
rows = { first: m, last: nrows-m-1 }
cols = { first: m, last: ncols-m-1 }
rect_size = 2 * (nrows + ncols) - 8*m - 4
rotations = n % rect_size
row = col = rrow = rcol = m
rotations.times { rrow, rcol = nxt(rows, cols, rrow, rcol) }
rect_size.times do
arr[row][col] = matrix[rrow][rcol]
row, col = nxt(rows, cols, row, col)
rrow, rcol = nxt(rows, cols, rrow, rcol)
end
end
arr
end
def first_replacement_loc(rows, cols, rotations)
ncm1 = cols[:last]-cols[:first]
nrm1 = rows[:last]-rows[:first]
return [rows[:first], cols[:first]+rotations] if rotations <= ncm1
rotations -= ncm1
return [rows[:first]+rotations, cols[:last]] if rotations <= nrm1
rotations -= nrm1
return [rows[:last], cols[:last]-rotations] if rotations <= ncm1
rotations -= ncm1
[rows[:last]-rotations, cols[:first]]
end
def cary2(matrix, n)
arr = matrix.dup.map(&:dup)
nrows, ncols = arr.size, arr.first.size
0.upto([nrows, ncols].min/2-1) do |m|
rows = { first: m, last: nrows-m-1 }
cols = { first: m, last: ncols-m-1 }
rect_size = 2 * (nrows + ncols) - 8*m - 4
rotations = n % rect_size
row = col = m
rrow, rcol = first_replacement_loc(rows, cols, rotations)
rect_size.times do
arr[row][col] = matrix[rrow][rcol]
row, col = nxt(rows, cols, row, col)
rrow, rcol = nxt(rows, cols, rrow, rcol)
end
end
arr
end
def humbledore(matrix, rotate)
rows, cols = matrix.size, matrix.first.size
layers, str_cols = [rows, cols].min / 2, ""
# cols.times do str_cols << "%5s " end
temp_rows = []
(0...layers).each do |layer|
row = []
(layer...rows - 1 - layer).each do |i|
row << matrix[i][layer]
end
(layer...cols - 1 - layer).each do |i|
row << matrix[rows - 1 - layer][i]
end
(rows - 1 - layer).step(layer + 1, -1).each do |i|
row << matrix[i][cols - 1 - layer]
end
(cols - 1 - layer).step(layer + 1, -1).each do |i|
row << matrix[layer][i]
end
temp_rows << row
end
result = (1..( rows * cols )).each_slice(rows).to_a
(0...layers).each do |layer|
row = temp_rows[layer]
shift = rotate % row.size
idx = -shift
(layer...rows - 1 - layer).each do |i|
result[i][layer] = row[idx]
idx += 1
idx %= row.size
end
(layer...cols - 1 - layer).each do |i|
result[rows - 1 - layer][i] = row[idx]
idx += 1
idx %= row.size
end
(rows - 1 - layer).step(layer + 1, -1).each do |i|
result[i][cols - 1 - layer] = row[idx]
idx += 1
idx %= row.size
end
(cols - 1 - layer).step(layer + 1, -1).each do |i|
result[layer][i] = row[idx]
idx += 1
idx %= row.size
end
end
result
end
require 'benchmark'
def test(rows, cols, rotations)
puts "\nrows = #{rows}, cols = #{cols}, rotations = #{rotations}"
matrix = (1..rows*cols).each_slice(cols).to_a
Benchmark.bm do |x|
x.report("Cary1") { cary1(matrix, rotations) }
x.report("Cary2") { cary2(matrix, rotations) }
x.report("Humbledore") { humbledore(matrix, rotations) }
end
end
test 10,10,1
rows = 10, cols = 10, rotations = 1
user system total real
Cary1 0.000000 0.000000 0.000000 ( 0.000077)
Cary2 0.000000 0.000000 0.000000 ( 0.000074)
Humbledore 0.000000 0.000000 0.000000 ( 0.000051)
test 10,10,78
rows = 10, cols = 10, rotations = 78
user system total real
Cary1 0.000000 0.000000 0.000000 ( 0.000079)
Cary2 0.000000 0.000000 0.000000 ( 0.000061)
Humbledore 0.000000 0.000000 0.000000 ( 0.000053)
test 100,100,378
rows = 100, cols = 100, rotations = 378
user system total real
Cary1 0.000000 0.000000 0.000000 ( 0.007673)
Cary2 0.015625 0.000000 0.015625 ( 0.005168)
Humbledore 0.000000 0.000000 0.000000 ( 0.002919)
test 500,500,1950
rows = 500, cols = 500, rotations = 1950
user system total real
Cary1 0.171875 0.000000 0.171875 ( 0.166671)
Cary2 0.140625 0.000000 0.140625 ( 0.137141)
Humbledore 0.046875 0.000000 0.046875 ( 0.053705)
test 500,1000,2950
rows = 500, cols = 1000, rotations = 2950
user system total real
Cary1 0.296875 0.000000 0.296875 ( 0.292997)
Cary2 0.234375 0.000000 0.234375 ( 0.248384)
Humbledore 0.125000 0.000000 0.125000 ( 0.103964)
Benchmark reports execution times in seconds. The results are found to be quite consistent.
Notice that in all of the tests I performed the number of columns of the array is at least as large as the number of rows. That's because a NoMethodError (undefined method '[]=' for nil:NilClass) exception was raised in Humbledore's code whenever the number of rows exceeded the number of columns. (Try test 3,2,1, for example.) The error message occurred in the second line of the following block of code.
(layer...cols - 1 - layer).each do |i|
result[rows - 1 - layer][i] = row[idx]
idx += 1
idx %= row.size
end
I expect the problem is easily fixable.

Removing elements from an array

Problem:
I have two arrays A and B:
A = [0, 1, 2, 3]; %A will always be from 0 to N where N in this case is 3.
B = [0, 1, 3, 1, 9, 4, 6, 2, 5, 9, 10, 11, 3, 8, 1, 5, 9, 10];
weights_B = [3, 4, 5, 6];
I want to compare the first element of A to the first 3 elements of B and the second element of A to the next 4 elements of B. If the elements of A are equal I remove it from B. So in example:
if (A(1) == B(1:3))
remove A(1) from B
Similarly,
I want to compare A(2) to the next 4 elements of B i.e. to B(4:7):
if (A(2) == B(4:7))
remove A(2) from B
I want to compare A(3) to the next 5 elements of B i.e. to B(8:12)
if (A(3) == B(8:12))
remove A(3) from B
I want to compare A(4) to the next 6 elements of B i.e. to B(13:18)
if (A(4) == B(13:18))
remove A(4) from B
Note: The array weights_B determines the number of elements in B that should be respectively compared to A(1), A(2), .. , A(4)
So in the end B should have the following elements:
B = [1, 3, 9, 4, 6, 5, 9, 10, 11, 8, 1, 5, 9, 10];
Needed Solution:
Is there any way I can do this without having to hard-code the indices?
Here's a way without hard-coding:
Bw = mat2cell(B, 1, weights_B); % split into chunks
result = cell(size(Bw)); % initiallize result
for k = 1: numel(A)
result{k} = Bw{k}(Bw{k}~=A(k)); % fill each chunk of the result
end
result = [result{:}]; % concatenate into a row vector
For the sake of diversity, here's a way to do this using splitapply:
function out = q50982235
A = 0:3;
B = [0, 1, 3, 1, 9, 4, 6, 2, 5, 9, 10, 11, 3, 8, 1, 5, 9, 10];
weights_B = [3, 4, 5, 6];
a_ind = 0; % acts as a "global" variable for the inner function
G = repelem( 1:numel(weights_B), weights_B ); % this creates a vector of groups
out = cell2mat( splitapply(#movdif, B, G) );
function out = movdif(B)
a_ind = a_ind + 1;
out = {B(B ~= A(a_ind))};
end
end
The above works because the order of processed groups is predictable.
This solution requires R2015b.
Try this
A = [0, 1, 2, 3];
B = [0, 1, 3, 1, 9, 4, 6, 2, 5, 9, 10, 11, 3, 8, 1, 5, 9, 10];
weights_B = A + A(end);
border_0 = zeros(size(A));
border_1 = zeros(size(A));
border_0(1) = 1;
border_1(end) = length(B);
for i= 2:length(A)
border_0(i) = border_0(i-1) + weights_B(i-1);
border_1(i-1) = border_0(i)-1;
end
C = [];
for i= 1:length(border_0)
shift = 0;
if (i > 1)
shift = border_1(i-1);
end
C = [C B( find(B(border_0(i):border_1(i))~=A(i)) + shift )]
end
A = [0, 1];
B = [0, 1, 3, 1, 4, 5, 6];
% Split B into cells
C{1} = B(1:3) ; % this can be coded if more splits are required
C{2} = B(4:end) ;
% removing the lements
for i = 1:2
C{i}(C{i}==A(i))=[] ; % remove the elements in C{i} present in A(i)
end
cell2mat(C)
Since you want to compare the elements of A with first 3 and then 4 elements of B respectively, you would need to involve indexes.
You could simply use loop for it.
for(int i=0;i<B.length;i++){
if((A[0]==B[i])&&i<3){
B[i]=B[i+1];
}
else if((A[0]==B[i])&&i>3){}
B[i]=B[i+1];
}
Then adjust the updated size of array B.

For each element in an array, if the element is less than its previous element, increase it till the previous element with one

Suppose I have an array: list1 = [8, 5, 3, 1, 1, 10, 15, 9]
Now if the element is less than its previous element, increase it till the previous element with one.
Here:
5 < 8 so 5 should become: 5 + 3 + 1 = 9 i.e (8+1)
3 < 5 so 3 should become: 3 + 2 + 1 = 6 i.e (5+1)
1 < 3 so 1 should become: 1 + 2 + 1 = 4 i.e (3+1)
Now I am able to get the difference between elements if its less than its previous element.
But, how to use it in a final list to get an output like this:
finallist = [8, 9, 6, 4, 1, 10, 15, 16]
Also how can I get a final list value of 'k' list in my code? Right now it shows:
[2]
[2, 4]
[2, 4, 3]
[2, 4, 3, 3]
[2, 4, 3, 3, 7]
Source code:
list1 = [8, 5, 3, 1, 1, 10, 15, 9]
k = []
def comput(x):
if i[x] < i[x-1]:
num = (i[x-1] - i[x]) + 1
k.append(num)
print(k)
return
for i in [list1]:
for j in range(len(list1)):
comput(j)
You can use a list comprehension for this. Basically, the following code will check if one is larger than the next. If it is, then it will convert it to the previous+1.
list1 = [8, 5, 3, 1, 1, 10, 15, 9]
k = [list1[0]] + [i if j<=i else j+1 for i,j in zip(list1[1:],list1[:-1])]
cost = [j-i for i,j in zip(list1,k)]
print(k)
print(cost)
Output:
[8, 9, 6, 4, 1, 10, 15, 16]
[0, 4, 3, 3, 0, 0, 0, 7]
The following code will create a new list with the required output
l1 = [8, 5, 3, 1, 1, 10, 15, 9]
l = [l1[0]]
c=[0] # cost / difference list
for i in range(len(l1)-1):
if l1[i+1] < l1[i]:
l.append(l1[i]+1)
c.append(l1[i]+1-l1[i+1])
else:
l.append(l1[i+1])
c.append(0)
print(l)
Output
[8, 9, 6, 4, 1, 10, 15, 16]
[0, 4, 3, 3, 0, 0, 0, 7]

Confusion with loops in C

i have to make a program with the following condition: A delivery guy deliver stacks(packs) of beer to different shops
1st shop, 1 stack
2nd shop, 2 stacks
3rd shop, 3 stacks
...
until 10th shop.
The program must print it like this :
int i1,shop[10]={1,2,3,4,5,6,7,8,9,10},stacks[10]={1,2,3,4,5,6,7,8,9,10},counter;
for (i1 = 9; i1 >= 0; i1--){
for(counter=0;counter<=i1;counter++){
printf("Shop[%i] %i \t",shop[i1], stacks[i1]);
}
It's running but the output is not what I want :
Shop[10] 10 Shop[10] 10 Shop[10] 10 Shop[10] 10
Shop[10] 10 Shop[10] 10 Shop[10] 10 Shop[10] 10
Shop[10] 10 Shop[10] 10 Shop[9] 9 Shop[9] 9
Shop[9] 9 Shop[9] 9 Shop[9] 9 Shop[9] 9
Shop[9] 9 Shop[9] 9 Shop[9] etc.
It must look like this:
Shop 1 - 1
Shop 2 - 2, 2
Shop 3 - 3, 3, 3
Shop 4 - 4, 4, 4, 4.
You've got your loops scrambled. Here is a piece of code that will print what you want. Modify the code so it access the right arrays and print their contents:
for(i = 1; i <= 10; i++) {
printf("Shop %d - ", i);
for(j = 1; j <= i; j++)
printf("%d, ", i);
putchar('\n');
}
The first loop (with i), will print the "Shop - " string, 10 times. The second loop will run for every iteration of the first loop, thus, giving you the correct numbers of prints. Minor code changes will take core of the comma printing...
Outputs:
Shop 1 - 1,
Shop 2 - 2, 2,
Shop 3 - 3, 3, 3,
Shop 4 - 4, 4, 4, 4,
Shop 5 - 5, 5, 5, 5, 5,
Shop 6 - 6, 6, 6, 6, 6, 6,
Shop 7 - 7, 7, 7, 7, 7, 7, 7,
Shop 8 - 8, 8, 8, 8, 8, 8, 8, 8,
Shop 9 - 9, 9, 9, 9, 9, 9, 9, 9, 9,
Shop 10 - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
You'll need to use multiple printf statements to produce each line of output. Put
printf( "Shop %d", i1 );
in your outer loop (no newline).
Within your inner loop, you'll just print out the value of stacks[i1] (again, with no newlines):
printf( " %d", stacks[i1] );
You'll have to write a newline in a separate statement after the inner loop has finished:
putchar( '\n' );
Don't worry about commas or other separators for now.
Make those changes, and that'll get you most of the way there.
Edit
Your inner loop should check against stacks[i1], rather than i1.
If you want your output to appear on separate lines you need to put in a \n new line character at the end of the string like this rather than the tab character you've got currently.
printf("Shop[%i] %i \n",shop[i1], stacks[i1]);
Fist of all, please get used to write clean code so its more readeable, and your question more organized. Is this what you want?
int i1;
int shop[10]={1,2,3,4,5,6,7,8,9,10};
int stacks[10]={1,2,3,4,5,6,7,8,9,10};
int counter;
//To go through the shops
for (i1 = 0; i1 < 10; i1++){
printf("Shop[%i] - ",i1);
//to go through the packs
for(counter=0;counter<=i1;counter++){
printf("%i", stacks[counter]);
}
printf("\n");
}
To output the pattern there is no need to use arrays. You can output it using loops.
For example
#include <stdio.h>
int main(void)
{
const unsigned int N = 10;
const char *Title = "Shop %u - %u";
for ( unsigned int i = 0; i < N; i++ )
{
unsigned int item = i + 1;
printf( Title, item, item );
for ( unsigned int j = 0; j < i; j++ )
{
printf( ", %u", item );
}
putchar( '\n' );
}
return 0;
}
The program output is
Shop 1 - 1
Shop 2 - 2, 2
Shop 3 - 3, 3, 3
Shop 4 - 4, 4, 4, 4
Shop 5 - 5, 5, 5, 5, 5
Shop 6 - 6, 6, 6, 6, 6, 6
Shop 7 - 7, 7, 7, 7, 7, 7, 7
Shop 8 - 8, 8, 8, 8, 8, 8, 8, 8
Shop 9 - 9, 9, 9, 9, 9, 9, 9, 9, 9
Shop 10 - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
Pay attention to that there is no redundant last comma in the output.
If to define the variable Title the following way
const char *Title = "Shop %2u - %u";
^^^
then the output will be more aligned.
Shop 1 - 1
Shop 2 - 2, 2
Shop 3 - 3, 3, 3
Shop 4 - 4, 4, 4, 4
Shop 5 - 5, 5, 5, 5, 5
Shop 6 - 6, 6, 6, 6, 6, 6
Shop 7 - 7, 7, 7, 7, 7, 7, 7
Shop 8 - 8, 8, 8, 8, 8, 8, 8, 8
Shop 9 - 9, 9, 9, 9, 9, 9, 9, 9, 9
Shop 10 - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
Also you could define the variable like
const char *Title = "Shop %2u - %2u";
^^^ ^^^
For example
#include <stdio.h>
int main(void)
{
const unsigned int N = 10;
const char *Title = "Shop %2u - %2u";
for ( unsigned int i = 0; i < N; i++ )
{
unsigned int item = i + 1;
printf( Title, item, item );
for ( unsigned int j = 0; j < i; j++ )
{
printf( ", %2u", item );
}
putchar( '\n' );
}
return 0;
}
The output is
Shop 1 - 1
Shop 2 - 2, 2
Shop 3 - 3, 3, 3
Shop 4 - 4, 4, 4, 4
Shop 5 - 5, 5, 5, 5, 5
Shop 6 - 6, 6, 6, 6, 6, 6
Shop 7 - 7, 7, 7, 7, 7, 7, 7
Shop 8 - 8, 8, 8, 8, 8, 8, 8, 8
Shop 9 - 9, 9, 9, 9, 9, 9, 9, 9, 9
Shop 10 - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10

Given a BST and its root, print all sequences of nodes which give rise to the same bst

Given a BST, find all sequences of nodes starting from root that will essentially give the same binary search tree.
Given a bst, say
3
/ \
1 5
the answer should be 3,1,5 and 3,5,1.
another example
5
/ \
4 7
/ / \
1 6 10
the outputs will be
5,4,1,7,6,10
5,4,7,6,10,1
5,7,6,10,4,1
etc
The invariant here however is that the parent's index must always be lesser than its children. I am having difficulty implementing it.
I assume you want a list of all sequences which will generate the same BST.
In this answer, we will use Divide and Conquer. We will create a function findAllSequences(Node *ptr) which takes a node pointer as input and returns all the distinct sequences which will generate the subtree hanging from ptr. This function will return a Vector of Vector of int, i.e. vector<vector<int>> containing all the sequences.
The main idea for generating sequence is that root must come before all its children.
Algorithm:
Base Case 1:
If ptr is NULL, then return a vector with an empty sequence.
if (ptr == NULL) {
vector<int> seq;
vector<vector<int> > v;
v.push_back(seq);
return v;
}
Base Case 2:
If ptr is a leaf node, then return a vector with a single sequence. Its Trivial that this sequence will contain only a single element, i.e. value of that node.
if (ptr -> left == NULL && ptr -> right == NULL) {
vector<int> seq;
seq.push_back(ptr -> val);
vector<vector<int> > v;
v.push_back(seq);
return v;
}
Divide Part (this part is very simple.)
We assume that we have a function that can solve this problem, and thus we solve it for left sub tree and right sub tree.
vector<vector<int> > leftSeq = findAllSeq(ptr -> left);
vector<vector<int> > rightSeq = findAllSeq(ptr -> right);
Merging the two solutions.(The crux is in this step.)
Till now we have two set containg distinct sequences:
i. leftSeq - all sequences in this set will generate left subtree.
ii. rightSeq - all sequences in this set will generate right subtree.
Now each sequence in left subtree can be merged with each sequence of right subtree. While merging we should be careful that the relative order of elements is preserved. Also in each of the merged sequence we will add the value of current node in the beginning beacuse root must come before all children.
Pseudocode for Merge
vector<vector<int> > results
for all sequences L in leftSeq
for all sequences R in rightSeq
create a vector flags with l.size() 0's and R.size() 1's
for all permutations of flag
generate the corresponding merged sequence.
append the current node's value in beginning
add this sequence to the results.
return results.
Explanation: Let us take a sequence, say L(of size n) from the set leftSeq, and a sequence, say R(of size m) from set rightSeq.
Now these two sequences can be merged in m+nCn ways!
Proof: After merging, the new sequence will have m + n elements. As we have to maintain the relative order of elements, so firstly we will fill all n the elements from L in any of n places among total (m+n) places. After that remaining m places can be filled by elements of R. Thus we have to choose n places from (m+n) places.
To do this, lets create take a Boolean vector, say flags and fill it with n 0's and m 1's.A value of 0 represents a member from left sequence and a value of 1 represents member from right sequence. All what is left is to generate all permutations of this flags vector, which can be done with next_permutation. Now for each permutation of flags we will have a distinct merged sequence of L and R.
eg: Say L={1, 2, 3} R={4, 5}
so, n=3 and m=2
thus, we can have 3+2C3 merged sequences, i.e. 10.
1.now, Initially flags = {0 0 0 1 1}, filled with 3 0's and 2 1's
this will result into this merged sequence: 1 2 3 4 5
2.after calling nextPermutation we will have
flags = {0 0 1 0 1}
and this will generate sequence: 1 2 4 3 5
3.again after calling nextPermutation we will have
flags = {0 0 1 1 0}
ans this will generate sequence: 1 2 4 5 3and so on...
Code in C++
vector<vector<int> > findAllSeq(TreeNode *ptr)
{
if (ptr == NULL) {
vector<int> seq;
vector<vector<int> > v;
v.push_back(seq);
return v;
}
if (ptr -> left == NULL && ptr -> right == NULL) {
vector<int> seq;
seq.push_back(ptr -> val);
vector<vector<int> > v;
v.push_back(seq);
return v;
}
vector<vector<int> > results, left, right;
left = findAllSeq(ptr -> left);
right = findAllSeq(ptr -> right);
int size = left[0].size() + right[0].size() + 1;
vector<bool> flags(left[0].size(), 0);
for (int k = 0; k < right[0].size(); k++)
flags.push_back(1);
for (int i = 0; i < left.size(); i++) {
for (int j = 0; j < right.size(); j++) {
do {
vector<int> tmp(size);
tmp[0] = ptr -> val;
int l = 0, r = 0;
for (int k = 0; k < flags.size(); k++) {
tmp[k+1] = (flags[k]) ? right[j][r++] : left[i][l++];
}
results.push_back(tmp);
} while (next_permutation(flags.begin(), flags.end()));
}
}
return results;
}
Update 3rd March 2017: This solution wont work perfectly if original tree contains duplicates.
Here is a clear, concise and well-documented solution that I wrote for you in Python 3. I hope it helps you!
Code: bst_sequences.py
from binarytree import bst, Node
def weave_lists(first: list, second: list, results: list, prefix: list) -> None:
"""Recursively Weave the first list into the second list and append
it to the results list. The prefix list grows by an element with the
depth of the call stack. Ultimately, either the first or second list will
be exhausted and the base case will append a result."""
# base case
if not first or not second:
results.append(prefix + first + second)
return
# recursive case
first_head, first_tail = first[0], first[1:]
weave_lists(first_tail, second, results, prefix + [first_head])
second_head, second_tail = second[0], second[1:]
weave_lists(first, second_tail, results, prefix + [second_head])
def all_sequences(root: Node) -> list:
"""Splits the tree into three lists: prefix, left, and right."""
if root is None:
return []
answer = []
prefix = [root.value]
left = all_sequences(root.left) or [[]]
right = all_sequences(root.right) or [[]]
# At a minimum, left and right must be a list containing an empty list
# for the following nested loop
for i in range(len(left)):
for j in range(len(right)):
weaved = []
weave_lists(left[i], right[j], weaved, prefix)
answer.extend(weaved)
return answer
if __name__ == "__main__":
t = bst(2)
print(t)
solution = all_sequences(t)
for e, item in enumerate(solution):
print(f"{e:03}: {item}")
Sample Output
__4
/ \
1 5
/ \ \
0 2 6
000: [4, 1, 0, 2, 5, 6]
001: [4, 1, 0, 5, 2, 6]
002: [4, 1, 0, 5, 6, 2]
003: [4, 1, 5, 0, 2, 6]
004: [4, 1, 5, 0, 6, 2]
005: [4, 1, 5, 6, 0, 2]
006: [4, 5, 1, 0, 2, 6]
007: [4, 5, 1, 0, 6, 2]
008: [4, 5, 1, 6, 0, 2]
009: [4, 5, 6, 1, 0, 2]
010: [4, 1, 2, 0, 5, 6]
011: [4, 1, 2, 5, 0, 6]
012: [4, 1, 2, 5, 6, 0]
013: [4, 1, 5, 2, 0, 6]
014: [4, 1, 5, 2, 6, 0]
015: [4, 1, 5, 6, 2, 0]
016: [4, 5, 1, 2, 0, 6]
017: [4, 5, 1, 2, 6, 0]
018: [4, 5, 1, 6, 2, 0]
019: [4, 5, 6, 1, 2, 0]
Process finished with exit code 0
I have a much shorter solution. What do you think about it?
function printSequences(root){
let combinations = [];
function helper(node, comb, others){
comb.push(node.values);
if(node.left) others.push(node.left);
if(node.right) others.push(node.right);
if(others.length === 0){
combinations.push(comb);
return;
}else{
for(let i = 0; i<others.length; i++){
helper(others[i], comb.slice(0), others.slice(0, i).concat(others.slice(i+1, others.length)));
}
}
}
helper(root, [], []);
return combinations;
}
Note that the question is actually about topological sorting of a tree: find all the possible ways to perform topological sort. That is, we don't care about the specific way the tree was built, what's important is that elements are always added as leaves, never changing the structure of existing nodes. The constraint on the output is that nodes never precede their ancestors - treating the tree as a classic dependency graph.
But unlike topological sort for a general DAG, there's no need for reference counting here, since this is a tree - the number of references is always 1 or 0.
Here's a simple Python implementation:
def all_toposorts_tree(sources, history):
if not sources:
print(history)
return
for t in sources:
all_toposorts((sources - {t}) | {t.left, t.right} - {None}, history + [t.v])
all_toposorts_tree({root}, [])
This is question 4.9 in Cracking the Coding Interview, 6th Edition.
well here is my python code which does producing all sequences of elements/numbers for same BST.
for the logic i referred to the book cracking the coding interview by Gayle Laakmann Mcdowell
from binarytree import Node, bst, pprint
def wavelist_list(first, second, wave, prefix):
if first:
fl = len(first)
else:
fl = 0
if second:
sl = len(second)
else:
sl = 0
if fl == 0 or sl == 0:
tmp = list()
tmp.extend(prefix)
if first:
tmp.extend(first)
if second:
tmp.extend(second)
wave.append(tmp)
return
if fl:
fitem = first.pop(0)
prefix.append(fitem)
wavelist_list(first, second, wave, prefix)
prefix.pop()
first.insert(0, fitem)
if sl:
fitem = second.pop(0)
prefix.append(fitem)
wavelist_list(first, second, wave, prefix)
prefix.pop()
second.insert(0, fitem)
def allsequences(root):
result = list()
if root == None:
return result
prefix = list()
prefix.append(root.value)
leftseq = allsequences(root.left)
rightseq = allsequences(root.right)
lseq = len(leftseq)
rseq = len(rightseq)
if lseq and rseq:
for i in range(lseq):
for j in range(rseq):
wave = list()
wavelist_list(leftseq[i], rightseq[j], wave, prefix)
for k in range(len(wave)):
result.append(wave[k])
elif lseq:
for i in range(lseq):
wave = list()
wavelist_list(leftseq[i], None, wave, prefix)
for k in range(len(wave)):
result.append(wave[k])
elif rseq:
for j in range(rseq):
wave = list()
wavelist_list(None, rightseq[j], wave, prefix)
for k in range(len(wave)):
result.append(wave[k])
else:
result.append(prefix)
return result
if __name__=="__main__":
n = int(input("what is height of tree?"))
my_bst = bst(n)
pprint(my_bst)
seq = allsequences(my_bst)
print("All sequences")
for i in range(len(seq)):
print("set %d = " %(i+1), end="")
print(seq[i])
example output:
what is height of tree?3
___12
/ \
__ 6 13
/ \ \
0 11 14
\
2
All sequences
set 1 = [12, 6, 0, 2, 11, 13, 14]
set 2 = [12, 6, 0, 2, 13, 11, 14]
set 3 = [12, 6, 0, 2, 13, 14, 11]
set 4 = [12, 6, 0, 13, 2, 11, 14]
set 5 = [12, 6, 0, 13, 2, 14, 11]
set 6 = [12, 6, 0, 13, 14, 2, 11]
set 7 = [12, 6, 13, 0, 2, 11, 14]
set 8 = [12, 6, 13, 0, 2, 14, 11]
set 9 = [12, 6, 13, 0, 14, 2, 11]
set 10 = [12, 6, 13, 14, 0, 2, 11]
set 11 = [12, 13, 6, 0, 2, 11, 14]
set 12 = [12, 13, 6, 0, 2, 14, 11]
set 13 = [12, 13, 6, 0, 14, 2, 11]
set 14 = [12, 13, 6, 14, 0, 2, 11]
set 15 = [12, 13, 14, 6, 0, 2, 11]
set 16 = [12, 6, 0, 11, 2, 13, 14]
set 17 = [12, 6, 0, 11, 13, 2, 14]
set 18 = [12, 6, 0, 11, 13, 14, 2]
set 19 = [12, 6, 0, 13, 11, 2, 14]
set 20 = [12, 6, 0, 13, 11, 14, 2]
set 21 = [12, 6, 0, 13, 14, 11, 2]
set 22 = [12, 6, 13, 0, 11, 2, 14]
set 23 = [12, 6, 13, 0, 11, 14, 2]
set 24 = [12, 6, 13, 0, 14, 11, 2]
set 25 = [12, 6, 13, 14, 0, 11, 2]
set 26 = [12, 13, 6, 0, 11, 2, 14]
set 27 = [12, 13, 6, 0, 11, 14, 2]
set 28 = [12, 13, 6, 0, 14, 11, 2]
set 29 = [12, 13, 6, 14, 0, 11, 2]
set 30 = [12, 13, 14, 6, 0, 11, 2]
set 31 = [12, 6, 11, 0, 2, 13, 14]
set 32 = [12, 6, 11, 0, 13, 2, 14]
set 33 = [12, 6, 11, 0, 13, 14, 2]
set 34 = [12, 6, 11, 13, 0, 2, 14]
set 35 = [12, 6, 11, 13, 0, 14, 2]
set 36 = [12, 6, 11, 13, 14, 0, 2]
set 37 = [12, 6, 13, 11, 0, 2, 14]
set 38 = [12, 6, 13, 11, 0, 14, 2]
set 39 = [12, 6, 13, 11, 14, 0, 2]
set 40 = [12, 6, 13, 14, 11, 0, 2]
set 41 = [12, 13, 6, 11, 0, 2, 14]
set 42 = [12, 13, 6, 11, 0, 14, 2]
set 43 = [12, 13, 6, 11, 14, 0, 2]
set 44 = [12, 13, 6, 14, 11, 0, 2]
set 45 = [12, 13, 14, 6, 11, 0, 2]
here is another concise recursion based easy to understand solution:
from binarytree import Node, bst, pprint
def allsequences1(root):
if not root:
return None
lt = allsequences1(root.left)
rt = allsequences1(root.right)
ret = []
if not lt and not rt:
ret.append([root])
elif not rt:
for one in lt:
ret.append([root]+one)
elif not lt:
for two in rt:
ret.append([root]+two)
else:
for one in lt:
for two in rt:
ret.append([root]+one+two)
ret.append([root]+two+one)
return ret
if __name__=="__main__":
n = int(input("what is height of tree?"))
my_bst = bst(n)
pprint(my_bst)
seg = allsequences1(my_bst)
print("All sequences ..1")
for i in range(len(seq)):
print("set %d = " %(i+1), end="")
print(seq[i])
Let's first observe what must be be followed to create the same BST. The only sufficient rules here is insert parent before their left and right children. Because, if we can guarantee that for some node (that we are interested to insert) all parents (including grand parent) are inserted but none of it's children are inserted, than the node will find its appropriate place to be inserted.
Following this observation we can write backtrack to generate all sequence that will produce same BST.
active_list = {root}
current_order = {}
result ={{}}
backtrack():
if(len(current_order) == total_node):
result.push(current_order)
return;
for(node in active_list):
current_order.push(node.value)
if node.left :
active_list.push(node.left)
if node.right:
active_list.push(node.right)
active_list.remove(node)
backtrack()
active_list.push(node)
if node.left :
active_list.remove(node.left)
if node.right:
active_list.remove(node.right)
current_order.remove(node.val)
This is not working implementation. used just for illustration purpose.
public class Solution {
ArrayList<LinkedList<Long>> result;
/*Return the children of a node */
ArrayList<TreeNode> getChilden(TreeNode parent) {
ArrayList<TreeNode> child = new ArrayList<TreeNode>();
if(parent.left != null) child.add(parent.left);
if(parent.right != null) child.add(parent.right);
return child;
}
/*Gets all the possible Compinations*/
void getPermutations(ArrayList<TreeNode> permutations, LinkedList<Long> current) {
if(permutations.size() == 0) {
result.add(current);
return;
}
int length = permutations.size();
for(int i = 0; i < length; i++) {
TreeNode node = permutations.get(i);
permutations.remove(i);
ArrayList<TreeNode> newPossibilities = new ArrayList<TreeNode>();
newPossibilities.addAll(permutations);
newPossibilities.addAll(getChilden(node));
LinkedList<Long> newCur = new LinkedList<Long>();
newCur.addAll(current);
newCur.add(node.val);
getPermutations(newPossibilities, newCur);
permutations.add(i,node);
}
}
/*This method returns a array of arrays which will lead to a given BST*/
ArrayList<LinkedList<Long>> inputSequencesForBst(TreeNode node) {
result = new ArrayList<LinkedList<Long>>();
if(node == null)
return result;
ArrayList<TreeNode> permutations = getChilden(node);
LinkedList<Long> current = new LinkedList<Long>();
current.add(node.val);
getPermutations(permutations, current);
return result;
}
}
My solution. Works perfectly.
Here's my Python solution with plenty of explanation.
We build each array from left to right by choosing for every position one node out of a set of possible choices for that position. We add the node value to the path, and the children of the node (if any) to the list of possibilities, then recurse further. When there are no further choices we have one candidate array. To generate the rest of the the arrays, we backtrack until we can make a different choice and recurse again.
The catch is to use a suitable data structure for holding the possibilities. A list works, but the node has to be put back in the previous position while backtracking (order matters, since we have added the children of the node which must be visited AFTER the node). Insertion and deletion from a list takes linear time. A set doesn't work since it doesn't maintain order. A dict works best since Python dictionary remembers the insertion order and all operations run in constant time.
def bst_seq(root: TreeNode) -> list[list[int]]:
def _loop(choices: MutableMapping[TreeNode, bool], path: list[int], result: list[list[int]]) -> None:
if not choices:
result.append([*path])
else:
# Take a snapshot of the keys to avoid concurrent modification exception
for choice in list(choices.keys()):
del choices[choice]
children = list(filter(None, [choice.left, choice.right]))
for child in children:
choices[child] = False
path.append(choice.val)
_loop(choices, path, result)
path.pop()
choices[choice] = False
for child in children:
del choices[child]
result = []
_loop({root: False}, [], result)
return result

Resources