AWK array seems to empty itself? - arrays

I am trying to learn awk by solving code puzzles. I am trying to read several "grids" of integers (representing bingo boards as per https://adventofcode.com/2021/day/4) into a three-dimensional awk array. An example "grid" can look like this:
22 13 17 11 0
8 2 23 4 24
21 9 14 16 7
6 10 3 18 5
1 12 20 15 19
And there are several of these in a longer input file. After reading each line into an array rows I am attempting to organize the numbers into this multi dimensional array called boards. Here is my example code:
{
b = 0
for (i in rows) {
split(rows[i], nums, " ")
for (j in nums) {
r = i % 5
n = j - 1
boards[b][r][n] = nums[j]
print b, r, n, nums[j], boards[b][r][n]
}
if (i%5==0)
++b
}
print boards[0][1][1]
}
Notice the debug printout print b, r, n, nums[j], boards[b][r][n] which indeed outputs the correct values for boards[b][r][n] on that row:
0 0 0 22 22
0 0 1 13 13
0 0 2 17 17
Etc. This seems to verify that the multi dimensional array gets written properly. Yet on the final line of the example code, the output is instead empty. I have tried using the form boards[b, r, n] for the array as well with the exact same result. Obviously there's something I'm not quite understanding here. Any help is appreciated. Full code for reproducibility:
# === ex.txt ===
7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1
22 13 17 11 0
8 2 23 4 24
21 9 14 16 7
6 10 3 18 5
1 12 20 15 19
3 15 0 2 22
9 18 13 17 5
19 8 7 25 23
20 11 10 24 4
14 21 16 12 6
14 21 17 24 4
10 16 15 9 19
18 8 23 26 20
22 11 13 6 5
2 0 12 3 7
# === solve.awk ===
BEGIN {
r = 0
}
{
if (NR == 1)
split($0, draws, "")
else if (NR != 2 && (NR-3)%6 != 5)
rows[r++] = $0
}
END {
b = 0
for (i in rows) {
split(rows[i], nums, " ")
for (j in nums) {
r = i % 5
n = j - 1
boards[b][r][n] = nums[j]
print b, r, n, nums[j], boards[b][r][n]
}
if (i%5==0)
++b
}
print boards[0][1][1]
}
I run this with awk -f solve.awk ex.txt. awk --version outputs GNU Awk 5.1.1, API: 3.1 (GNU MPFR 4.1.0-p13, GNU MP 6.2.1) as its first line. Thank you!

You are incrementing b at the end of the first iteration of your for (i in rows) loop because i == 0 ==> i%5 == 0, while you want to do it at the end of the 5th iteration. Try if (i%5 == 4) ++b.
Note that as you use GNU awk you could simplify all this. When the record separator (RS) is the empty string the records are separated by empty lines (one record per board):
$ awk -v RS='' '
NR>1 {
a[NR-2][1]; split($0, a[NR-2]);
}
END {
for(b in a) for(r in a[b])
boards[b][int((r-1)/5)][(r-1)%5] = a[b][r];
for(b in boards) for(r in boards[b]) for(n in boards[b][r])
print b, r, n, boards[b][r][n]
}' ex.txt
0 0 0 22
0 0 1 13
0 0 2 17
0 0 3 11
0 0 4 0
0 1 0 8
...

Related

How does 'While' loop and 'for' loop build in programming languages?

suddenly a question goes over my mind which is how the WHILE loop and FOR loop has been built into programming languages
and can we make something like it and write it the same way we write the loops?
I tried to make this code in dart language but it doesn't work and doesn't seem to be like the normal FOR loop
dynamic forLoop(condition, body){
if(condition){
body();
forLoop(condition, body);
}
}
void main(){
forLoop( (Something.i<5), (){print(Something.i); Something.i++;} );
}
I saw a similar question for Python for loop.
I tried the same approach using dis module for while loop.
def f():
n = 0
while n < 2:
print("body")
n += 1
return None
dis.dis(f)
2 0 LOAD_CONST 1 (0)
2 STORE_FAST 0 (n)
3 4 LOAD_FAST 0 (n)
6 LOAD_CONST 2 (2)
8 COMPARE_OP 0 (<)
10 POP_JUMP_IF_FALSE 18 (to 36)
4 >> 12 LOAD_GLOBAL 0 (print)
14 LOAD_CONST 3 ('body')
16 CALL_FUNCTION 1
18 POP_TOP
5 20 LOAD_FAST 0 (n)
22 LOAD_CONST 4 (1)
24 INPLACE_ADD
26 STORE_FAST 0 (n)
3 28 LOAD_FAST 0 (n)
30 LOAD_CONST 2 (2)
32 COMPARE_OP 0 (<)
34 POP_JUMP_IF_TRUE 6 (to 12)
6 >> 36 LOAD_CONST 0 (None)
38 RETURN_VALUE
You can find details about Python Bytecode Instructions in the dis module.

Extract a subarray

I have managed to transfer the 2d array int a 1d array to make it simpler. So given:
local table = {0,0,0,0,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,26,27,28,29,0,30,31,32,33, 0,34,35,36,37, 0 }
How can I extract a sub-array as below?
local sub = {2,3,4,7,8,9,12,13,14,17,18,19,22,23,24}
Here's one way...
> t = {}
> for i = 7, 30, 5 do
>> for j = i, i + 2 do
>> t[#t+1] = ble[j]
>> end
>> end
> for k,v in ipairs(t) do print(k,v) end
1 2
2 3
3 4
4 7
5 8
6 9
7 12
8 13
9 14
10 17
11 18
12 19
13 22
14 23
15 24
>
I renamed your table to ble so it doesn't shadow the table library.

Extract equally spaced subarrays from an array

I have an array:
v = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20];
I want to extract multiple arrays of length 3 equally spaced by 6 elements, starting at the fifth element of v, and then combine them together:
v1 = [5 6 7];
v2 = [11 12 13];
v3 = [17 18 19];
v_combined = [5 6 7 11 12 13 17 18 19];
Are there any simple ways to do this without using a for loop?
You can do it using logical indexing. You need to create an index mask like this
idx = [0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0]
which you can create like this:
idx = false(size(v))
k = 5
idx(k:end) = ~mod(floor((0:numel(v)-k)/3),2)
And finally
v_combined = v(idx)
In general for m elements spaces by n elements starting from k you can use
k=5;
m=3;
n=6;
I=1:numel(v);
v_combined = v((I>=k) & mod(I-k,n)<m)

What algorithm maps number 27 to BBC

To clarify the confusion - I want to write a function that maps a number to the following list of letter combinations.
My question is best illustrated with the following table.
A 1
B 2
C 3
AA 4
AB 5
AC 6
BA 7
BB 8
BC 9
CA 10
CB 11
CC 12
AAA 13
AAB 14
AAC 15
ABA 16
ABB 17
ABC 18
ACA 19
ACB 20
ACC 21
BAA 22
BAB 23
BAC 24
BBA 25
BBB 26
BBC 27
I want to design a function that is able to map a given number, to the left column of this here table. I've tried assigning numerals to the letters first.
A = 0
B = 1
C = 2
This allows me form the following table (Cn - Column number, from right to left).
C3 C2 C1 Number
0 1
1 2
2 3
0 0 4
0 1 5
0 2 6
1 0 7
1 1 8
1 2 9
2 0 10
2 1 11
2 2 12
0 0 0 13
0 0 1 14
0 0 2 15
0 1 0 16
0 1 1 17
0 1 2 18
0 2 0 19
0 2 1 20
0 2 2 21
1 0 0 22
1 0 1 23
1 0 2 24
1 1 0 25
1 1 1 26
1 1 2 27
So this looks like an recursive loop type algorithm, but I can't figure out how to put this down in code. Any suggestions?
As whoever the person was (user: n.m.) who wrote the comment that disappeared, this is just base-3 counting, except all numerals are offset by +1. The digits really stand for A=0, B=1, C=2
Hence BBC = ('B'+1)*3^2 + ('B'+1)*3 + ('C'+1) = 2*9 + 2*3 + 3 = 27
The pseudocode for fromInt(), Antoine has already given you it. Same idea:
char* fromInt(int n) {
result = ""
working_val = (n-1)
while (working_val>0) {
Prepend to result the digit "CAB"[ working_val % 3 ]
working_val /= 3
}
return result
}
Strictly we don't care about catching the special-case 0 which Antoine noted, because your list doesn't have a representation for 0.
#include <stdio.h>
#include <string.h>
int toInt(const char *str, int acc) {
if(*str)
return toInt(++str, acc * 3 + *str - 'A' + 1);
else
return acc;
}
char *fromInt(int n, char *outbuff){
char* p = outbuff;
while(n){
*p++ = 'A' + ((n % 3 == 0)? 3 : n % 3) - 1;
n = (n - 1) / 3;
}
*p = '\0';
return strrev(outbuff);//strrev isn't ANSI C
}
int main(void) {
char buff[] = "BBC";
int x = toInt(buff, 0);
printf("%d\n", x);
printf("%s\n", fromInt(x, buff));
return 0;
}
This is a kind of base-3 system, but the digits are 1 (A), 2 (B) and 3 (C), there is no 0.
The conversion formula from this representation is, as usual,
3^n*a_n + 3^(n-1)*a_{n-1} + ... + 3^0*a_0
The reverse conversion is just like a regular conversion to base 3, the only difference is that a modified remainder function is used:
int modified_remainder(m, n)
{
int answer = m % n;
if (answer == 0) answer = n;
return answer;
}
Now given the number m, the last digit of its representation would be
a_0 = modified_remainder(m, 3)
The one before last is
m_1 = (m - a_0) / 3; // m-a_0 is always divisible by 3
a_1 = modified_remainder(m_1, 3)
The next one is
m_2 = (m_1 - a_1) / 3
a_2 = modified_remainder(m_2, 3)
and so on. You stop when m_k < n.
Try to verify these claims, it's a good exercise.

Array a[i] prints in descending order, but my logic is for ascending order [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 years ago.
Improve this question
Can you please tell me why I am always getting array a[i] in descending order only? Please help.
for(i=0;i<10;i++)
{
for (j=0;j<10;j++)
{
if(a[i]>=a[j])
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
The problem is that your sorting runs two complete loops, comparing as for all pairs of i and j, including ones where i is greater than j (at which point you shouldn't be swapping the items). In order for selection sort * to work, it needs to pick its swap candidates only from the unsorted portion of the array.
Here is how to fix your implementation:
for(i=0;i<10-1;i++) // You do not need to touch the last element, so end at 10-1
{
for (j=i+1;j<10;j++) // Make it j = i+1
{
if(a[i] > a[j]) // >, not >= : no need to swap when two items are equal
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
* Selection Sort is the fancy name of the sorting algorithm that you are implementing.
Can you please tell me why I am always getting array a[i] in descending order only?
Because you implemented logic (comparisons) for descending order. Change
if(a[i]>=a[j])
to
if(a[i] < a[j])
See the code:
#include <stdio.h>
int main()
{
int a[10] = {3,15,9,4,15,65,0,2,1,1};
int temp;
for(int i=0;i<10;i++)
{
for (int j=0;j<10;j++)
{
if(a[j] > a[i])
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
for(int i=0;i<10;i++)
printf("%d ", a[i]);
}
Here is the working code with output: http://ideone.com/DijpJD.
Steps of sorting process: Only those steps are shown where the changes has taken place.
Pass 1: 15 3 9 4 15 65 0 2 1 1
65 3 9 4 15 15 0 2 1 1
Pass 2: 3 65 9 4 15 15 0 2 1 1
Pass 3: 3 9 65 4 15 15 0 2 1 1
Pass 4: 3 4 65 9 15 15 0 2 1 1
3 4 9 65 15 15 0 2 1 1
Pass 5: 3 4 9 15 65 15 0 2 1 1
Pass 6: 3 4 9 15 15 65 0 2 1 1
Pass 7: 0 4 9 15 15 65 3 2 1 1
0 3 9 15 15 65 4 2 1 1
0 3 4 15 15 65 9 2 1 1
0 3 4 9 15 65 15 2 1 1
0 3 4 9 15 15 65 2 1 1
Pass 8: 0 2 4 9 15 15 65 3 1 1
0 2 3 9 15 15 65 4 1 1
0 2 3 4 15 15 65 9 1 1
0 2 3 4 9 15 65 15 1 1
0 2 3 4 9 15 15 65 1 1
Pass 9: 0 1 3 4 9 15 15 65 2 1
0 1 2 4 9 15 15 65 3 1
0 1 2 3 9 15 15 65 4 1
0 1 2 3 4 15 15 65 9 1
0 1 2 3 4 9 15 65 15 1
0 1 2 3 4 9 15 15 65 1
Pass 10: 0 1 1 3 4 9 15 15 65 2
0 1 1 2 4 9 15 15 65 3
0 1 1 2 3 9 15 15 65 4
0 1 1 2 3 4 15 15 65 9
0 1 1 2 3 4 9 15 65 15
0 1 1 2 3 4 9 15 15 65

Resources