| View previous topic :: View next topic |
| Author |
Message |
juanamores Master
Joined: 15 Mar 2015 Posts: 317
|
Posted: Sun Apr 16, 2017 10:38 am Post subject: Sort file data |
|
|
I have a file that stores 2 data:
a name and a numerical value.
It stores them as follows:
| Code: | set fname "ranking"
set fp [open $fname "a"]
puts $fp "$name" "$value"
close $fp |
Content of the file "ranking":
| Quote: | Ana 5
Pedro 9
José 18
Luis 3
Maria 22
... more data... |
I want to sort the names of the maximum value to the minimum value, to obtain this result:
| Quote: | Maria 22
José 18
Pedro 9
Ana 5
Luis 3
... more data... |
What procedure do I have to follow so that the names are sorted with the values that correspond to them? _________________ If you do not understand my ideas is because I can not think in English, I help me with Google Translate. I only speak Spanish. Bear with me. Thanks  |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sun Apr 16, 2017 11:34 am Post subject: Re: Sort file data |
|
|
Play with this:
| Code: |
# April 15, 2017
# http://forum.egghelp.org/viewtopic.php?t=20326
bind pub - !do_sort read_and_sort
proc read_and_sort {nick uhost handle chan text} {
## You need to edit the following line
set fname "scripts/added/experimenting_for_somebody/ranking.txt"
set fp [open $fname "r"]
set data [read -nonewline $fp]
close $fp
set lines [split $data "\n"]
putserv "privmsg $chan :lines is: $lines"
putserv "privmsg $chan :sorted lines is: [lsort -integer -decreasing -index 1 $lines]"
}
|
Try it in a private test channel.
It will produce this, in your channel:
| Quote: |
<botnick> lines is: {Ana 5} {Pedro 9} {Jos� 18} {Luis 3} {Maria 22}
<botnick> sorted lines is: {Maria 22} {Jos� 18} {Pedro 9} {Ana 5} {Luis 3}
|
I hope that helps to get you started.
Reference:
http://www.tcl.tk/man/tcl8.6/TclCmd/lsort.htm
and
http://forum.egghelp.org/viewtopic.php?t=6885 _________________ For a fun (and popular) Trivia game, visit us at: irc.librairc.net #science-fiction . Over 300K Q & A to play in BogusTrivia ! |
|
| Back to top |
|
 |
juanamores Master
Joined: 15 Mar 2015 Posts: 317
|
Posted: Sun Apr 16, 2017 12:22 pm Post subject: |
|
|
Thanks for the help willyw.
Now that I think about it, I realize that my code will not work properly ...
The values that are stored are daily and correspond to the points obtained by each of the nicksnames.
On the same day, a nickname can get different scores ...
I think the script should be more complex and when retrieving the data, averaging between the values of each nick, and then ordering them at the end of the month.
The daily content of the ranking file will look something like this:
| Quote: | Ana 5
Pedro 9
Jose 18
Luis 3
Maria 22
Ana 15
Maria 3
Jose 2
Pedro 10
Ana 11
Pedro 4
Luis 3
Maria 15
Maria 18
Ana 14
Maria 3
Ana 2 |
From these data, I want to get the average of ordered values of each nick.
Pedro's average 9+10+4= 23 23/3= 7.66 Rounded value 8
Jose's average 18+2= 20 20/2= 10
Luis's average 3+3= 6 6/2= 3
Maria's average 22+3+15+18+3= 61 61/5= 12.2 Rounded value 12
Ana's average 15+11+14+2= 42/4= 10.5 Rounded value 10
I think the best way to store the points of each nick is horizontal line (Excel spreadsheet style), to facilitate calculations without repeating the nicks name.
Example:
Pedro 9 10 4
Jose 18 2
Luis 3 3
Maria 22 3 15 18 3
Ana 15 11 14 2
Final result ordered and averaged:
| Quote: | Pedro 8
Jose 10
Luis 3
Maria 12
Ana 10 |
The process must detect if the name exists in the file and if it exists put the value in the last place on the right that is not occupied by another value.
It's more complicated than I initially thought.
If you can think of any idea to achieve it, I will be very grateful. _________________ If you do not understand my ideas is because I can not think in English, I help me with Google Translate. I only speak Spanish. Bear with me. Thanks  |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sun Apr 16, 2017 12:40 pm Post subject: |
|
|
| juanamores wrote: |
...
and correspond to the points obtained by each of the nicksnames.
On the same day, a nickname can get different scores ...
|
I guess you're running some kind of game.
Remember - we haven't seen it, and have no idea what you're talking about.
| Quote: |
...The process ...
|
"The process" ??
What process? I don't know what you're talking about... yet.
| Quote: |
.... put the value ..."
|
What value?
| Quote: |
in the last place on the right that is not occupied by another value.
It's more complicated than I initially thought.
If you can think of any idea to achieve it, I will be very grateful. |
The problem now is that I don't have a clear picture of what you are doing. So I don't know what you want to do, and can't think on it, as to what might be best. _________________ For a fun (and popular) Trivia game, visit us at: irc.librairc.net #science-fiction . Over 300K Q & A to play in BogusTrivia ! |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sun Apr 16, 2017 1:55 pm Post subject: |
|
|
In the meantime, here's something to experiment with:
| Code: |
# April 15, 2017
# http://forum.egghelp.org/viewtopic.php?t=20326
bind pub - !do_sort read_and_sort
proc read_and_sort {nick uhost handle chan text} {
## reference: http://forum.egghelp.org/viewtopic.php?t=6885
## Edit the following line
set fname "scripts/added/experimenting_for_somebody/ranking.txt"
set fp [open $fname "r"]
set data [read -nonewline $fp]
close $fp
set lines [split $data "\n"]
putserv "privmsg $chan :lines is: $lines"
###putserv "privmsg $chan :sorted lines is: [lsort -integer -decreasing -index 1 $lines]"
foreach el $lines {
set the_nick [lindex $el 0]
set scoreslist [lrange $el 1 end]
## reference : http://wiki.tcl.tk/819#pagetoc9326db77
## : http://wiki.tcl.tk/951
set avgscore [ expr ([join $scoreslist +])/[llength $scoreslist] ]
set new_el "$the_nick $avgscore"
lappend new_list $new_el
}
putserv "privmsg $chan : "
putserv "privmsg $chan :new_list is: $new_list"
putserv "privmsg $chan :sorted new_list is: [lsort -integer -decreasing -index 1 $new_list]"
}
|
This:
| Quote: |
Example:
Pedro 9 10 4
Jose 18 2
Luis 3 3
Maria 22 3 15 18 3
Ana 15 11 14 2
|
produces this:
| Quote: |
<botnick> lines is: {Pedro 9 10 4} {Jose 18 2} {Luis 3 3} {Maria 22 3 15 18 3} {Ana 15 11 14 2 }
<botnick>
<botnick> new_list is: {Pedro 7} {Jose 10} {Luis 3} {Maria 12} {Ana 10}
<botnick> sorted new_list is: {Maria 12} {Jose 10} {Ana 10} {Pedro 7} {Luis 3}
|
_________________ For a fun (and popular) Trivia game, visit us at: irc.librairc.net #science-fiction . Over 300K Q & A to play in BogusTrivia ! |
|
| Back to top |
|
 |
caesar Mint Rubber

Joined: 14 Oct 2001 Posts: 3741 Location: Mint Factory
|
Posted: Sun Apr 16, 2017 2:02 pm Post subject: |
|
|
Have a look at:
| Code: |
# read the ranking file
set fp [open "ranking.txt" "r"]
set data [read -nonewline $fp]
close $fp
# loop through the read data
foreach line [split $data "\n"] {
# if the file doesn't have a name and rank disregard it
if {[scan $line {%s%d} name rank] != 2} continue
lappend ranking($name) $rank
}
# load each value in the array and make the result
foreach name [array names ranking] {
set total 0
# count the number of ranks
set count [llength $ranking($name)]
# sum the ranks
foreach no $ranking($name) {
incr total $no
}
# make the average
set result [expr $total / $count]
# output the result
putlog "name: $name | result: $result"
}
|
Result:
| Quote: |
name: Ana result: 8
name: Luis result: 3
name: Jose result: 7
name: Maria result: 10
name: Pedro result: 6
|
Your welcome.  _________________ Once the game is over, the king and the pawn go back in the same box. |
|
| Back to top |
|
 |
juanamores Master
Joined: 15 Mar 2015 Posts: 317
|
Posted: Mon Apr 17, 2017 11:44 am Post subject: |
|
|
The idea of caesar is not exactly what I had in mind, but it works!
I have modified the format to two decimal places of the variable count, to round off the final result.
| Code: | # count the number of ranks format 2 decimal
set count [format "%.2f" [llength $ranking($name)]] |
| Code: | # output the rounded result
putlog "name: $name | result: [expr round ($result)]" |
Now, I need to sort from highest to lowest results.
Instead of this:
| Quote: | name: Ana result: 8
name: Luis result: 3
name: Jose result: 7
name: Maria result: 10
name: Pedro result: 6
|
I want to get this:
| Quote: | name: Maria result: 10
name: Ana result: 8
name: Jose result: 7
name: Pedro result: 6
name: Luis result: 3
|
The caesar's code with my small modifications:
| Code: | bind pub - !avgs averages
proc averages {nick uhost hand chan text} {
# read the ranking file
set fp [open "ranking" "r"]
set data [read -nonewline $fp]
close $fp
# loop through the read data
foreach line [split $data "\n"] {
# if the file doesn't have a name and rank disregard it
if {[scan $line {%s%d} name rank] != 2} continue
lappend ranking($name) $rank
}
# load each value in the array and make the result
foreach name [array names ranking] {
set total 0
# count the number of ranks format 2 decimal
set count [format "%.2f" [llength $ranking($name)]]
# sum the ranks
foreach no $ranking($name) {
incr total $no
}
# make the average
set result [expr $total / $count]
# output the rounded result
putlog "name: $name | result: [expr round ($result)]"
}
}
|
Now I need to sort the results, from highest to lowest.
willyw, I appreciate your contributions, it is not a game, I did not copy more code because I only need to sort the values of a file.
caesar understood my idea, now I just need to modify the caesar's code to get the ranking ordered from highest to lowest. _________________ If you do not understand my ideas is because I can not think in English, I help me with Google Translate. I only speak Spanish. Bear with me. Thanks  |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Mon Apr 17, 2017 11:49 am Post subject: |
|
|
| juanamores wrote: |
Now I need to sort the results, from highest to lowest.
willyw, I appreciate your contributions, it is not a game, I did not copy more code because I only need to sort the values of a file.
caesar understood my idea, now I just need to modify the caesar's code to get the ranking ordered from highest to lowest. |
Ok.
I showed you one way to sort it, above. You can adapt from that.
Good luck with it.  _________________ For a fun (and popular) Trivia game, visit us at: irc.librairc.net #science-fiction . Over 300K Q & A to play in BogusTrivia ! |
|
| Back to top |
|
 |
caesar Mint Rubber

Joined: 14 Oct 2001 Posts: 3741 Location: Mint Factory
|
Posted: Mon Apr 17, 2017 12:15 pm Post subject: |
|
|
| Code: |
bind pub - !avgs averages
proc averages {nick uhost hand chan text} {
set fp [open "ranking" "r"]
set data [read -nonewline $fp]
close $fp
foreach line [split $data "\n"] {
if {[scan $line {%s%d} name rank] != 2} continue
lappend ranking($name) $rank
}
foreach name [array names ranking] {
set total 0
set count [llength $ranking($name)]
foreach no $ranking($name) {
incr total $no
}
set average [expr round ([expr $total / $count])]
lappend result($name) $average
}
set data [lsort -stride 2 -index 1 -integer -decreasing [array get result]]
foreach {name score} $data {
putlog "$name $score"
}
}
|
Should do what you wanted.
| Quote: |
Maria 12
Jose 10
Ana 9
Pedro 8
Luis 3
|
If you want to get an rounded result like:
| Quote: |
Maria 12.20
Jose 10.00
Ana 9.40
Pedro 7.67
Luis 3.00
|
then replace:
| Code: |
set average [expr round ([expr $total / $count])]
and
set data [lsort -stride 2 -index 1 -integer -decreasing $data]
|
with:
| Code: |
set average [format "%.2f" [expr $total / $count]]
and
set data [lsort -stride 2 -index 1 -real -decreasing $data]
|
_________________ Once the game is over, the king and the pawn go back in the same box. |
|
| Back to top |
|
 |
juanamores Master
Joined: 15 Mar 2015 Posts: 317
|
Posted: Mon Apr 17, 2017 12:33 pm Post subject: |
|
|
| willyw wrote: | | I showed you one way to sort it, above. You can adapt from that. |
In your solution, you get the result by sorting a list, but with the caesar code I have to sort an array.
I haven't idea how to integrate both ideas...  _________________ If you do not understand my ideas is because I can not think in English, I help me with Google Translate. I only speak Spanish. Bear with me. Thanks  |
|
| Back to top |
|
 |
caesar Mint Rubber

Joined: 14 Oct 2001 Posts: 3741 Location: Mint Factory
|
Posted: Mon Apr 17, 2017 12:42 pm Post subject: |
|
|
Here's a clean and a lot shorter code:
| Code: |
bind pub - !avgs averages
proc averages {nick uhost hand chan text} {
set fp [open "ranking" "r"]
set data [read -nonewline $fp]
close $fp
foreach line [split $data "\n"] {
if {[scan $line {%s%d} name rank] != 2} continue
lappend ranking($name) $rank
}
foreach {name values} [array get ranking] {
set average [expr ([join $values +]) / [llength $values]]
lappend result($name) $average
}
set results [lsort -stride 2 -index 1 -integer -decreasing [lsort -stride 2 -index 0 [array get result]]]
foreach {name score} $results {
putlog "$name $score"
}
}
|
The result is the same:
| Quote: |
Maria 12
Jose 10
Ana 9
Pedro 7
Luis 3
|
The data I used is from what you posted at your second comment. Isn't the result what you are looking for?
Edit: Shorted the code removing unnecessarily loops. Don't know why I didn't think about this in the first place.
Second edit: Since your initial list doesn't have two names with an identical result I didn't see:
| Quote: |
Maria 12
Jose 10
Ana 9
Pedro 7
Luis 3
Ben 3
|
Notice that the list is sorted only by average (descending) and member names aren't sorted so to get them sorted as well changed the code to first sort by name as a secondary key and then sort by average (descending) as a primary key.
So we:
| Code: |
# build a flat list
set results [array get result]
# sort by name as a secondary key
set results [lsort -stride 2 -index 0 $result]
# then sort by average (descending) as a primary key.
set results [lsort -stride 2 -index 1 -integer -decreasing $results]
|
and all 3 lines combined:
| Code: |
set results [lsort -stride 2 -index 1 -integer -decreasing [lsort -stride 2 -index 0 [array get result]]]
|
Result:
| Quote: |
Maria 12
Jose 10
Ana 9
Pedro 7
Ben 3
Luis 3
|
Is this final result what you where looking for?  _________________ Once the game is over, the king and the pawn go back in the same box.
Last edited by caesar on Mon Apr 17, 2017 1:33 pm; edited 1 time in total |
|
| Back to top |
|
 |
juanamores Master
Joined: 15 Mar 2015 Posts: 317
|
Posted: Mon Apr 17, 2017 1:31 pm Post subject: |
|
|
caesar your code gives an error:
| Quote: | Tcl error [averages]: bad option "-stride": must be -ascii, -command, -decreasing, -dictionary, -increasing, -index, -indices, -integer, -nocase, -real, or -unique
|
_________________ If you do not understand my ideas is because I can not think in English, I help me with Google Translate. I only speak Spanish. Bear with me. Thanks  |
|
| Back to top |
|
 |
caesar Mint Rubber

Joined: 14 Oct 2001 Posts: 3741 Location: Mint Factory
|
Posted: Mon Apr 17, 2017 1:35 pm Post subject: |
|
|
You seem to have an old TCL library, cos stride is in version 8.6 and upwards. Since I got 8.6 I can't test if replacing:
| Code: |
set results [lsort -stride 2 -index 1 -integer -decreasing [lsort -stride 2 -index 0 [array get result]]]
|
with:
| Code: |
set results [lsort -index 1 -integer -decreasing [lsort -index 0 [array get result]]]
|
will work so let me know to find another solution. _________________ Once the game is over, the king and the pawn go back in the same box. |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Mon Apr 17, 2017 1:35 pm Post subject: |
|
|
| juanamores wrote: | caesar your code gives an error:
| Quote: | Tcl error [averages]: bad option "-stride": must be -ascii, -command, -decreasing, -dictionary, -increasing, -index, -indices, -integer, -nocase, -real, or -unique
|
|
do:
.status
in the partyline, and note the version of TCL your bot is using, and post it here for caesar .
edit:
We posted at the exact same time!  _________________ For a fun (and popular) Trivia game, visit us at: irc.librairc.net #science-fiction . Over 300K Q & A to play in BogusTrivia ! |
|
| Back to top |
|
 |
juanamores Master
Joined: 15 Mar 2015 Posts: 317
|
Posted: Mon Apr 17, 2017 1:39 pm Post subject: |
|
|
| Quote: | running eggdrop v1.6.21
Tcl version: 8.5.13 (header version 8.5.13) |
_________________ If you do not understand my ideas is because I can not think in English, I help me with Google Translate. I only speak Spanish. Bear with me. Thanks  |
|
| Back to top |
|
 |
|