Reputation: 1994
In a past paper for an exam I have the question:
Months can be represented in different ways, for example as numbers (1, 2, …, 12), or as three- letter month names (Jan, Feb, …, Dec). Suggest how associative arrays in awk can be used to translate from three-letter month names to month numbers, and vice versa, to translate month numbers to three-letter month names.
So I thought I would use associative arrays in the format say the input of the month is in $1:
number_to_month["Jan"] = 1;
print number_to_month[$1]
But to me this doesn't seem to leverage the power of associative arrays very well, plus I have to initialise each month in the array manually.
What are my other options?
Upvotes: 4
Views: 4121
Reputation: 247042
Here's another take, using a couple of helper functions:
awk '
BEGIN {
j = 0
for (i=1; i<=34; i+=3) {
months[substr("JanFebMarAprMayJunJulAugSepOctNovDec",i,3)] = ++j
}
}
function month2num(month) {
return (month in months ? months[month] : -1)
}
function num2month(n) {
for (month in months) {
if (months[month] == n)
return month
}
return ""
}
BEGIN {
print "Jan: " month2num("Jan")
print "Dec: " month2num("Dec")
print "Foo: " month2num("Foo")
print "3: " num2month(3)
print "12: " num2month(12)
print "14: " num2month(14)
}
'
Upvotes: 0
Reputation: 204229
$ cat tst.awk
BEGIN {
mths="JanFebMarAprMayJunJulAugSepOctNovDec"
name="Mar"; print name " -> " (match(mths,name)+2)/3
name="Sep"; print name " -> " (match(mths,name)+2)/3
nbr=3; print nbr " -> " substr(mths,(nbr*3)-2,3)
nbr=9; print nbr " -> " substr(mths,(nbr*3)-2,3)
}
$ awk -f tst.awk
Mar -> 3
Sep -> 9
3 -> Mar
9 -> Sep
and here's @dmckee's script modified to produce ordered output:
$ cat tst2.awk
BEGIN {
n = split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",month)
for (i in month) {
month_nums[month[i]]=i
}
for (i=1; i<=n; i++) {
print i "\t" month[i]
}
for (i=1; i<=n; i++) {
m = month[i]
print m "\t" month_nums[m]
}
}
$ awk -f tst2.awk
1 Jan
2 Feb
3 Mar
4 Apr
5 May
6 Jun
7 Jul
8 Aug
9 Sep
10 Oct
11 Nov
12 Dec
Jan 1
Feb 2
Mar 3
Apr 4
May 5
Jun 6
Jul 7
Aug 8
Sep 9
Oct 10
Nov 11
Dec 12
Upvotes: 1
Reputation: 17014
In case you do not want to initialize array manually, one option is:
echo | awk '{x=mktime("2013 01 01 0 0 0"); for(i=0;i<12;i++){s=strftime("%b",x+((31*i)*86400)); m[s]=i+1;n[i+1]=s;}}'
This will create 2 arrays, m & n, where m is the array in which index is the month name and value is month number, and the n array is vice-versa.
Upvotes: 2
Reputation: 101251
The builtin split
function is your friend here, and looping can copy the name-from-number version into the number-from-name:
BEGIN {
split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",month)
for (i in month) {
month_nums[month[i]]=i
}
}
END {
for (i in month) {
print i "\t" month[i]
}
for (m in month_nums) {
print m "\t" month_nums[m]
}
}
The BEGIN
block shows how to do it. Then END
block just lets you verify it.
The output I get (using gawk 4.0.1) is:
4 Apr
5 May
6 Jun
7 Jul
8 Aug
9 Sep
10 Oct
11 Nov
12 Dec
1 Jan
2 Feb
3 Mar
Feb 2
Sep 9
Jan 1
May 5
Apr 4
Oct 10
Dec 12
Nov 11
Jul 7
Mar 3
Aug 8
Jun 6
notice the usual awkwardness (Heh! AWKwardness) arrising from the inability to force the access order on array for
loops.
Upvotes: 7
Reputation: 721
When they mention awk, I presume this details of months and integer mapping is maintained in data file like
1 JAN JANUARY jan
2 FEB FEBRUARY feb
...
and so on
you can use awk
awk '/JAN/ {print $1}' temp.txt
Upvotes: 0