egghelp.org community Forum Index
[ egghelp.org home | forum home ]
egghelp.org community
Discussion of eggdrop bots, shell accounts and tcl scripts.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Sort file data
Goto page 1, 2  Next
 
Post new topic   Reply to topic    egghelp.org community Forum Index -> Scripting Help
View previous topic :: View next topic  
Author Message
juanamores
Master


Joined: 15 Mar 2015
Posts: 317

PostPosted: Sun Apr 16, 2017 10:38 am    Post subject: Sort file data Reply with quote

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 Smile
Back to top
View user's profile Send private message
willyw
Owner


Joined: 15 Jan 2009
Posts: 921

PostPosted: Sun Apr 16, 2017 11:34 am    Post subject: Re: Sort file data Reply with quote

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
View user's profile Send private message
juanamores
Master


Joined: 15 Mar 2015
Posts: 317

PostPosted: Sun Apr 16, 2017 12:22 pm    Post subject: Reply with quote

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 Smile
Back to top
View user's profile Send private message
willyw
Owner


Joined: 15 Jan 2009
Posts: 921

PostPosted: Sun Apr 16, 2017 12:40 pm    Post subject: Reply with quote

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
View user's profile Send private message
willyw
Owner


Joined: 15 Jan 2009
Posts: 921

PostPosted: Sun Apr 16, 2017 1:55 pm    Post subject: Reply with quote

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
View user's profile Send private message
caesar
Ass Kicker


Joined: 14 Oct 2001
Posts: 3401
Location: Area 51

PostPosted: Sun Apr 16, 2017 2:02 pm    Post subject: Reply with quote

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. Smile
_________________
You may say anything about me, but don't misspell my name.
Back to top
View user's profile Send private message
juanamores
Master


Joined: 15 Mar 2015
Posts: 317

PostPosted: Mon Apr 17, 2017 11:44 am    Post subject: Reply with quote

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. Smile


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 Smile
Back to top
View user's profile Send private message
willyw
Owner


Joined: 15 Jan 2009
Posts: 921

PostPosted: Mon Apr 17, 2017 11:49 am    Post subject: Reply with quote

juanamores wrote:

Now I need to sort the results, from highest to lowest. Smile

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. Smile
_________________
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
View user's profile Send private message
caesar
Ass Kicker


Joined: 14 Oct 2001
Posts: 3401
Location: Area 51

PostPosted: Mon Apr 17, 2017 12:15 pm    Post subject: Reply with quote

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]

_________________
You may say anything about me, but don't misspell my name.
Back to top
View user's profile Send private message
juanamores
Master


Joined: 15 Mar 2015
Posts: 317

PostPosted: Mon Apr 17, 2017 12:33 pm    Post subject: Reply with quote

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... Embarassed
_________________
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 Smile
Back to top
View user's profile Send private message
caesar
Ass Kicker


Joined: 14 Oct 2001
Posts: 3401
Location: Area 51

PostPosted: Mon Apr 17, 2017 12:42 pm    Post subject: Reply with quote

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. Rolling Eyes

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? Smile
_________________
You may say anything about me, but don't misspell my name.


Last edited by caesar on Mon Apr 17, 2017 1:33 pm; edited 1 time in total
Back to top
View user's profile Send private message
juanamores
Master


Joined: 15 Mar 2015
Posts: 317

PostPosted: Mon Apr 17, 2017 1:31 pm    Post subject: Reply with quote

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 Smile
Back to top
View user's profile Send private message
caesar
Ass Kicker


Joined: 14 Oct 2001
Posts: 3401
Location: Area 51

PostPosted: Mon Apr 17, 2017 1:35 pm    Post subject: Reply with quote

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.
_________________
You may say anything about me, but don't misspell my name.
Back to top
View user's profile Send private message
willyw
Owner


Joined: 15 Jan 2009
Posts: 921

PostPosted: Mon Apr 17, 2017 1:35 pm    Post subject: Reply with quote

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! Smile
_________________
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
View user's profile Send private message
juanamores
Master


Joined: 15 Mar 2015
Posts: 317

PostPosted: Mon Apr 17, 2017 1:39 pm    Post subject: Reply with quote

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 Smile
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    egghelp.org community Forum Index -> Scripting Help All times are GMT - 4 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Forum hosting provided by Reverse.net

Powered by phpBB © 2001, 2005 phpBB Group
subGreen style by ktauber