-1

I have a file which contains records like those:

434419\Teclu\Tudor\1501\9502
187650\Cosma\Sorin\1504\9253
239474\Teclu\Daniel\1502\5245
844936\Gaman\Mihai\1505\4074
942341\Avram\Tudor\1505\4543
137158\Gaman\Marius\1505\5244
531747\Francu\Daniel\1503\2226
382144\Teclu\Daniel\1501\9943
913409\Gaman\Mihai\1501\5473
901028\Avram\Mihai\1502\6169
382207\Dedu\Alex\1504\5428
726697\Gaman\Sorin\1502\5071
271503\Gaman\Ionut\1505\6643
147791\Dedu\Dragos\1503\4955
495572\Cosma\Alex\1505\9750
769482\Popescu\Sorin\1505\5472
410724\Marin\Mihai\1502\7317
381000\Marin\Daniel\1503\7321
251934\Popescu\Ionut\1504\8288
416161\Gaman\Mihai\1501\8245
523401\Gaman\Mihai\1504\3101
347491\Avram\Daniel\1504\2017
329372\Dedu\Sorin\1502\8528
509554\Popescu\Ionut\1502\7972

Fields delimited by \ . First field is an ID, second is surname, 3rd is first name, 4th wage and 5th performance score.

I have to write a script that takes one argument which is a surname and find the person(s) with that name in the first and last 10 lines of the file. Then from those extract the person with the lowest wage or if there are 2 or more with the same name and the same wage compare their performance score and take the one with the bigger score. For this person, I must print the ID.

I tried a combination of head tail cut and some more commands:

{ head -n 10 file.txt ; tail -n 10 file.txt } | grep $NAME | sort -t '\' -r k 4

to sort by wage from lowest to highest but I don't know what to do next if the wages are equal.

  • You can use -k multiple times in a single sort command – blissini Nov 18 '16 at 20:28
0

Keeping the beginning of your command:

{ head -n 10 file.txt ; tail -n 10 file.txt; } |
grep $NAME | sort -t '\' -k 4 -k 5 |
awk -F'\\' '!wage{wage=$4;id=$1;next} wage==$4{id=$1} END{print id}'

The awk script basically puts into formula the textual description you gave of the algorithm.

Of course, you could also replace the first 3 commands in the pipe with some more awk logic, like:

$ myFun() {
    awk -F'\\' -v s=$2 -v l=`wc -l<$1` '
      $2==s&&(NR<11||NR>l-11)&&(!wage||wage>$4||(wage==$4&&$5>perf)){
        wage=$4; id=$1; perf=$5;
      }
      END{ print id; }' $1; }
$ myFun exampleData.dsv Teclu
382144
$ myFun exampleData.dsv Gaman
416161

Note to OP in comment: The '$1', '$2', etc. variables in awk are independent of the outer shell variables of the same name.

  • thank you but how do you use awk in a script that already has $1 as argument – adikinzor Nov 18 '16 at 21:26
  • @adikinzor, $1 means something completely different to Awk than to your shell. See here. – Wildcard Nov 18 '16 at 23:15
0

TXR Lisp:

(defstruct person ()
  id last first wage score
  (:method equal (me)
    (list (- me.wage) me.score)))

(let* ((surname (pop *args*))
       (database (build (awk (:set fs "\\")     ;; backslash field sep
                             ((fconv i - - i i) ;; int, noconv, noconv, int, int
                              (add (new person
                                        id [f 0] last [f 1] first [f 2]
                                        wage [f 3] score [f 4])))))))
  (del [database 10..-10]) ;; drop all but first/last ten
  (let* ((select-surname (keep-if (op equal @1.last surname) database))
         (best (find-max select-surname)))
    (put-line (if best `best ID: @{best.id}` "notfound"))))

Tests:

$ txr process.tl nonexistent data
notfound
$ txr process.tl Teclu data
best ID: 382144
$ txr process.tl Gaman data
best ID: 416161
$ txr process.tl Popescu data
best ID: 509554
$ txr process.tl Francu data
best ID: 531747

The trick here of why we can use a simple (find-max select-surname) (i.e. apply the find-max function to the database filtered down by surname) to find the best ID is the equality substitution method defined for the person struct:

(:method equal (me)
  (list (- me.wage) me.score))

When this method exists, then whenever an object of this type is compared using equal, less or greater, or hashed in :equal-based hash tables and such, then that object's equal method is called and the returned value is used in its place. So here what we are saying is that two person objects are compared on equality using a list consisting of their negated wage (so lower is better) and their score. From there, regular TXR Lisp semantics of list equality/inequality applies:

1> (greater '(1 1) '(1 0))
t
2> (greater '(1 1) '(1 2))
nil
3> (greater '(2 1) '(1 2))
t

The corresponding first elements are compared, and if they are equal, then the second and so on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.