How to interpolate an array in 'awk'? - arrays

we would like to interpolate data within in array using 'awk'. I have an array
1 1 3 3 ...
3 3 5 3
5 5 6 5
6 6 6 5
for which we would like to obtain
1 1 3 3 ...
2 2 4 4
3 3 5 3
4 4 5.5 4
5 5 6 5
6 6 6 5
Doing so would allow us to have a complete array covering all possible data for the first column, representing a timeline. Column 2 and more are data. The matrix is of size of 4x110100. We have this script:
awk '
{
P[$1]=$2
I[i++]=$1
}
END{
j=0; s=I[j]; t=I[j+1]
for(i=m;i<=n;i++){
if(I[j+2] && i>t){
j++; s=I[j]; t=I[j+1]
}
print i,P[s]+(i-s)*(P[t]-P[s])/(t-s)
}
}' m=1 n=6 f1.dat > f2.dat
but it only does it for the first two columns as
1 1
2 2
3 3
4 4
5 5
6 6
How could we extend the interpolation to the entire array?! I have tried with 'for' or 'while' scripts, but we cannot achieve the aim...

You can do this by keeping track of just the current and previous lines:
BEGIN {
# initialise "previous" line
getline;
for (i=0; i<=NF; i++) p[i] = $i;
}
{
# print previous line
print p[0];
# check if column 1 has skipped
if ( (d = $1-p[1]) > 1 ) {
# if so, insert (d-1) new rows
for (i=1; i<d; i++) {
# interpolate values for each column
for (c=1; c<=NF; c++) {
printf "%s%s",
p[c] + (i/d)*($c-p[c]), # linear interpolation
c==NF ? ORS : OFS; # avoid trailing spaces
}
}
}
# update previous line
for (i=0; i<=NF; i++) p[i] = $i;
}
END {
# print the final line
print p[0];
}

Related

How to create a Sudoku grid with the following pattern in C without arrays?

I have to create a Sudoku grid with the following pattern in C:
1 2 3 4
3 4 1 2
2 3 4 1
4 1 2 3
The first number in the top left corner (here: 1) must be an editable variable for a start value. There is another variable to create the grid with by the square size, in this example the square size is 2 and the 1 2 3 4 are in one square. 3 4 1 2 are in another square and so on...
If the start value is e.g. 3, the grid looks like this:
3 4 1 2
1 2 3 4
4 1 2 3
2 3 4 1
I noticed that there is a pattern: If the row number is odd, the new start value of the next row is the second last one. If the row number is even, the new start value of the next row is the last one. I tried to do it in C, but the even rows are cloning themselves. Note that arrays and pointers are not allowed here, only loops and other control-structures.
I tried the following approach, but the even rows are cloning themselves:
#include <stdio.h>
const int intSquareSize = 2;
const int intFieldLength = intSquareSize * intSquareSize;
int intStartValue = 3;
int main() {
int a = 0;
int b = 0;
int m = 0;
for (int intRowCounter = 1; intRowCounter <= intFieldLength; intRowCounter++) {
m = intFieldLength - 1;
for (int intColumnCounter = 1; intColumnCounter <= intFieldLength; intColumnCounter++) {
a = intStartValue + (intColumnCounter - 1);
b = a;
if (a > intFieldLength) {
a = intFieldLength - m;
m--;
}
if (intRowCounter % 2 == 0 && intColumnCounter == intFieldLength) {
intStartValue = a;
} else if (intRowCounter % 2 == 1 && intColumnCounter == (intFieldLength - 1)) {
intStartValue = b;
}
printf("%d\t", a);
}
printf("\n");
}
return 0;
}
What did I wrong and how can I fix it?
If the row number is odd, the new start value of the next row is the second last one. If the row number is even, the new start value of the next row is the last one.
I don't think it is helpful to think in terms of odd and even. The involved numbers are just symbols, and one could even replace them with distinct colors (for example). Odd/even is not a significant thing here, and it would certainly not play the same role in other board sizes.
The pattern I see is this:
In the first intSquareSize rows, the values shift horizontally (compared to the previous row) by intSquareSize. For example with intSquareSize=3 the first three rows could be:
3 4 5 6 7 8 9 1 2
6 7 8 9 1 2 3 4 5
9 1 2 3 4 5 6 7 8
Notice the shift of 3 positions to the left at each next row.
Then the pattern for the next chunks of intSquareSize rows would be the same, but with one shift. So the complete 9x9 sudoku would look like this:
3 4 5 6 7 8 9 1 2
6 7 8 9 1 2 3 4 5
9 1 2 3 4 5 6 7 8
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
1 2 3 4 5 6 7 8 9
5 6 7 8 9 1 2 3 4
8 9 1 2 3 4 5 6 7
2 3 4 5 6 7 8 9 1
This is just one possible pattern you could follow. There could be others. But the following code will apply the above logic. Note I used your variables, but I prefer to use 0-based logic, so loop variables start at 0, and the value of a is also 0-based. Only at the time of printing 1 is added to that value, so it becomes 1-based:
int a = intStartValue - 1; // Move from 1-based to 0-based
for (int intBlockCounter = 0; intBlockCounter < intSquareSize; intBlockCounter++) {
for (int intRowCounter = 0; intRowCounter < intSquareSize; intRowCounter++) {
for (int intColumnCounter = 0; intColumnCounter < intFieldLength; intColumnCounter++) {
printf("%d\t", (a + 1)); // back to 1-based
a = (a + 1) % intFieldLength;
}
printf("\n");
a = (a + intSquareSize) % intFieldLength; // Shift within a block
}
a = (a + 1) % intFieldLength; // Shift between blocks
}

How do we make arrays in awk?

{
k = 0
x = 0
fracon = (10/2)+1
{
for (j = 1; j <= 1100 ; j++)
{
if (j <= fracon)
scal[j]= j-x
else
k= k + 1
scal[j]= j - (2*k)
{
if (scal[j] == 1)
fracon= fracon+11
{
if (j % 11 == 0)
x=x+11
k=k+0.5
}
}
}
}
}
That's all. I used the above code to generate the following array. It works in Matlab, but it does not work in awk.
array= [1 2 3 4 5 6 5 4 3 2 1 1 2 3 4 5 6]
here is another way of generating the same sequence
$ awk 'BEGIN{for(i=0;i<=20;i++) {k=i%11+1; printf "%s ", (k<7?k:12-k)}; print ""}'
1 2 3 4 5 6 5 4 3 2 1 1 2 3 4 5 6 5 4 3 2
not sure what you want is just repeated on a 11 element cycle or not; difficult to say based on limited sample.
or without awk
$ yes $({ seq 6; seq 5 -1 1; } | paste -sd' ') | head -100 | paste -sd' '
1 2 3 4 5 6 5 4 3 2 1 1 2 3 4 5 6 5 4 3 2 1 ...
with square brackets
$ awk 'BEGIN{printf "[";
for(i=0;i<=1100;i++) {k=i%11+1; printf "%s ", (k<7?k:12-k)};
printf "]\n"}'
[1 2 3 4 5 6 5 4 3 2 1 1 2 3 4 5 6 ... 5 4 3 2 1 ]
Stuffing these values into a large array is not optimal, you can write a function to return the indexed value easily
$ awk 'function k(i,_i) {_i=i%11+1; return _i<7?_i:12-_i}
BEGIN{for(i=0;i<=25;i++) print k(i)}'
in the real code, you'll use k(i) instead of printing. Note the array index starts from 0.
N.B. the _i is a local variable in the awk function; you don't need to use in the call syntax.

Improper Initialization of 2D Array in C

I am trying to construct a 2D array for an assignment. I've used a nested for loop to construct the 2D array using scanf():
int width;
int height;
scanf("%d %d",&width,&height);
int array[width][height];
for (int i=0;i<height;i++){
for (int j=0;j<width;j++){
scanf("%d",&array[i][j]);
}
}
However when I print the array, I can see that it has been constructed in a strange way, where all the numbers of the first line past a certain point are the first few numbers from the second line (instead of what they should be). The next lines after work fine.
Example:
Input:
6 2
1 3 5 7 9 1
2 4 6 8 0 2
3 4 2 0 1 3
The created array looks like this:
1 3 2 4 6 8 (<-- these last 4 numbers are the first 4 numbers of the second line)
2 4 6 8 0 2 (correct)
3 4 2 0 1 3 (correct)
Any ideas? Thanks a lot.
Your declaration of array
int array[width][height];
is wrong. The outer loop goes from 0 to height - 1, but array[i] can only go
from 0 to width - 1. The same applies for the inner loop. You swapped width
and height in the declaration of the array, it should be
int array[height][width];
Also note that for the matrix
1 3 5 7 9 1
2 4 6 8 0 2
3 4 2 0 1 3
the width is 6 and the height is 3, so the correct input should be
6 3
1 3 5 7 9 1
2 4 6 8 0 2
3 4 2 0 1 3
I compiled and run this code:
#include <stdio.h>
int main(void)
{
int width;
int height;
scanf("%d %d",&width,&height);
int array[height][width];
for (int i=0;i<height;i++){
for (int j=0;j<width;j++){
scanf("%d",&array[i][j]);
}
}
printf("----------------\n");
for (int i=0;i<height;i++){
for (int j=0;j<width;j++){
printf("%d ", array[i][j]);
}
printf("\n");
}
}
And the output is:
$ ./b
6 3
1 3 5 7 9 1
2 4 6 8 0 2
3 4 2 0 1 3
----------------
1 3 5 7 9 1
2 4 6 8 0 2
3 4 2 0 1 3
as you can see, now it's reading correctly. See https://ideone.com/OJjj0Y

Array processing, shapes

I have a square 2d array of values, where each row is identical, and where each element of row is one bigger than the last. For example:
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
I want to filter them, such that I can make a diamond as such:
1
1 2 3
1 2 3 4 5
1 2 3 4 5 6 7
1 2 3 4 5
1 2 3
1
Notice how the first part of the array is used, no matter how many elements are to be printed on that line. Also, spacing doesn't matter. I spaced them to show the diamond.
I know how to filter the top right "chunk" out, using j-i<(j/2). This will convert the original square into:
1
1 2 3
1 2 3 4 5
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
How can I get the bottom right "chunk" to filter out also? What additional condition can I impose on the values?
Presuming you have found out and stored the length of the "side" of the square already then you could use something like below. However, if your square has an even length then it will not work (can't produce a diamond in this way from an even side length square).
The following is pseudo-code so you will need to adapt it for your language. I've also used 0-indexed arrays and presumed square is a 2D array.
for (i=0, i<length, i++)
{
for (j=0, j<Length, j++)
{
if (i < length/2)
{
if (j < length/2 AND j <= i)
print square[i][j]
}
}
else
{
if (j < length/2 AND j <= (length - i))
{
print square[i][j]
}
}
}
print newline
}

Need help with logic (C)

I need to swap first n elements from two non repeating sequences(arrays), where n is a random integer.
Seq1: 1 4 5 6 9 8 2 3 7
Seq2: 3 9 1 2 8 7 4 5 6
If n = 4
Seq1: 3 9 1 2 | 9 8 2 3 7
Seq2: 1 4 5 6 | 8 7 4 5 6
Now i need to repair the sequence by replacing the repeated numbers after '|'.
How to do this?
This is my effort..
for(left1 = 0; left1<pivot; left1++)
{
for(right1 = pivot; right1 < no_jobs; right1++)
{
if(S1->sequence[left1] == S1->sequence[right1])
{
for(left2 = 0; left2<pivot; left2++)
{
for(right2 = pivot; right2<no_jobs; right2++)
{
if(S2->sequence[left2] == S2->sequence[right2])
{
swap_temp = S1->sequence[right1];
S1->sequence[right1] = S2->sequence[right2];
S2->sequence[right2] = swap_temp;
break;
}
}
}
}
}
}
Swapping the first n elements is straightforward using a single for loop.
for(int i = 0; i < n; i++){
int tmp = array1[i];
array1[i] = array2[i];
array2[i] = tmp;
}
Now you need to find what has changed in the arrays. You can do this by comparing the parts you swapped.
int m1 = 0, m2 = 0;
int missing_array1[n];
int missing_array2[n];
for(int i = 0; i < n; i++){
bool found = false;
for(int j = 0; j < n; j++){
if(array1[i] == array2[j]){
found = true;
break;
}
}
if(!found){
missing_array2[m2++] = array1[i];
}
}
for(int i = 0; i < n; i++){
bool found = false;
for(int j = 0; j < n; j++){
if(array2[i] == array1[j]){
found = true;
break;
}
}
if(!found){
missing_array1[m1++] = array2[i];
}
}
missing_array2 now contains the numbers that are missing from array2. These are all the numbers that will be duplicated in array1. The same goes for missing_array1. Next you need to scan both arrays and replace the duplicates with the missing numbers.
while(m1 >= 0){
int z = 0;
while(missing_array1[m1] != array2[n + z]){
z++;
}
array2[n + z] = missing_array2[m1--];
}
while(m2 >= 0){
int z = 0;
while(missing_array2[m2] != array1[n + z]){
z++;
}
array1[n + z] = missing_array1[m2--];
}
In summary, you compare the parts you swapped to find the values that will be missing from each array. These value are also the values that will be duplicated in the opposite array. Then you scan each of the arrays and replace the duplicate values with one of the missing values (I assume you don't care which of the missing values, as long as all the values are unique.
If the swapped portions of the sequences contain the same values, then there would be no repeats - performing the swap would just shuffle the first n elements. So the values you need to repair are the values which occur in one of the swapped sequences
Firstly, I'd create a histogram of the n swapped elements, with those from sequence 1 counting as bit 0, and those from sequence 2 as bit 1. If any members of the histogram are non-zero, then they occur in one or the other sequence only.
If there are values requiring repair, then you can construct a look-up table of the values which require rewriting. This should map i to i unless i is one of the asymmetric values in the histogram, in which case it needs to map to the another asymmetric value.
Seq1: 1 4 5 6 9 8 2 3 7
Seq2: 3 9 1 2 8 7 4 5 6
If n = 4
Seq1: 3 9 1 2 | 9 8 2 3 7
Seq2: 1 4 5 6 | 8 7 4 5 6
histogram
value 1 2 3 4 5 6 7 8 9
count 3 1 1 2 2 2 0 0 1
mapping for sequence 1 ( while histogram [S1[i]] & 1, replace[S1[i]] with S2[i] )
value 1 2 3 4 5 6 7 8 9
replace 1 6 5 4 5 6 7 8 4
apply mapping to sequence 1 for i > n
Seq1: 3 9 1 2 | 9 8 2 3 7
replace - - - - | 4 8 6 5 7
result 3 9 1 2 | 4 8 6 5 7
mapping for sequence 2 ( while histogram [S2[i]] & 2, replace[S2[i]] with S1[i] )
value 1 2 3 4 5 6 7 8 9
replace 1 2 3 9 3 2 7 8 9
apply mapping to sequence 1 for i > n
Seq2: 1 4 5 6 | 8 7 4 5 6
replace - - - - | 8 7 9 3 2
result 1 4 5 6 | 8 7 9 3 2
Alternatively, replace with the next value with the other bit set in the histogram (the iterated replace will also need to check for replacing a value with itself); I'm assuming it doesn't really matter what value is used as the replacement as long as the values in the result are unique.

Resources