mIRC Homepage
Posted By: sparta hash table question - 27/08/10 09:41 PM
I have been trying to solve a problem a while now, i got items stored in a table the format is:

hadd table date. $+ $nick $date

This add the nick with a date in the table, and i want to remove the last one if the table is full. the table can hold 1000 items, and so far i have 786 stored items, how can i remove the oldest item so the table wont be full when im up to 1000 and i want to add one more, maybe somone have a bether idea then the use of $date ..
Posted By: pball Re: hash table question - 27/08/10 10:01 PM
well from what you said I get the impression you think there is a limited number of items you can add. You can add as many things to a hash table as you wish if that's your concern. Read the help if you don't believe me.

If you would just want to limit it to a max of 1000 regardless of their being no limit. I believe hash tables always add more items to the "end" so you could just remove the first item in the table. Which you can get the name by using $hget(tablename,1).item
Posted By: starbucks_mafia Re: hash table question - 27/08/10 11:14 PM
Quote:

If you would just want to limit it to a max of 1000 regardless of their being no limit. I believe hash tables always add more items to the "end" so you could just remove the first item in the table. Which you can get the name by using $hget(tablename,1).item

No a hash table is an unsorted structure, there is no beginning or end. $hget(tablename, 1).item will return an arbitrary item completely unrelated to the order it was added.
Posted By: pball Re: hash table question - 27/08/10 11:26 PM
whoops, didn't think of that.

Then I guess you'd have to loop through each item and find the oldest value. If you want just the oldest item, I'd suggesting using $ctime, which is just the amount of time in seconds from date. You can convert it to a normal form of date also. I suggest using $ctime since the smaller the number the older the date and the easier to compare it is.
Posted By: starbucks_mafia Re: hash table question - 27/08/10 11:27 PM
Is there any particular reason you are using a hash table to store this information? It seems like you would be better off using an ordered method of storing information such as a window or file.

In that case you could use aline to add entries and something like:
if ($line(@mydata,0) > 1000) dline @mydata 1- $+ $calc($v1 - 1000)
to trim it down to 1000 entries.
Posted By: pball Re: hash table question - 27/08/10 11:43 PM
the following code finds the oldest value in the hast table test with the following format.
//hadd test date.pball $ctime
Just call the alias and it echos the oldest item and then deletes it
Code:
alias oldest {
  set -l %num 1
  set -l %oldest $ctime
  while ($hget(test,%num).data) {
    if ($hget(test,%num).data < %oldest) { set -l %oldest $v1 | set -l %item $hget(test,%num).item }
    inc %num
  }
  echo -a %item
  hdel test %item
}


warning this could take a while with 1000 entries and you could call it like if ($hget(test,0).item == 1000) oldest
Posted By: DJ_Sol Re: hash table question - 27/08/10 11:57 PM
Just so you know, hmake table 1000 does not make 1000 slots for data.

If you still want to delete the last item you need to know what order they are in. What you can do is add a number to the name.

/hadd table $+($calc($hget(table,0).item + 1),date.,$nick) $date

When I make the table I'm getting the total number of items in the table and adding 1 to it. I used the $+ identifier to join the data.

So your entry will look like.

1date.Nickname date

Now if you want to remove the last number, you can use $hget(table,0).item to get your total number. So if that returns 756, you know to delete 756.

If you want to delete the top 10 you know its 746 - 756.

var %x = $hget(table,0).item, %y = $calc(%x - 10)

You can use /hdel -w table 756* to delete it.


Quote:
maybe somone have a bether idea then the use of $date ..

I don't know why you want to store the date. Thats up to you.
Posted By: sparta Re: hash table question - 28/08/10 07:44 AM
I trying to make a seen script, and i add every nick to the hash table with..
Code:
on *:join:#: {
  if ($nick != $me) && ($seen.chans == $true) {
      hadd seen action. $+ $nick join
      hadd seen channel. $+ $nick $chan
      hadd seen time. $+ $nick $ctime
      hadd seen network. $+ $nick $network
    }
  }
}

and i want the script to clear out the oldest data, not that good if you let the table be to big.

I removed the date part
Posted By: Thels Re: hash table question - 28/08/10 05:29 PM
If you're not using any other identifiers, you'll have to find the one with the lowest time.

Code:
while $hfind(seen, time.*, 0, w) > 999 {

  ;Set %time to $ctime at start. Compare all entries to this %time variable.
  var %time $ctime

  ;Check all time. entries.
  var %count 0
  while %count < 1000 {
    var %count $calc(%count + 1)
    var %entry $hfind(seen, time.*, %count, w)

    ;If the value for this entry is lower than %time, this is the lowest entry found so far.
    if $hget(seen, %entry) < %time {
      var %time $hget(seen, %entry)
      var %nick $right(%entry, -5)
    }
  }

  ;Remove the oldest entry
  hdel seen action. $+ %nick
  hdel seen channel. $+ %nick
  hdel seen time. $+ %nick
  hdel seen network. $+ %nick
}


Put the code in your on join script or in it's own alias, and whenever there are more than 999 entries, it will keep deleting the highest entry until 999 are left.

PS. it might be smarter to base your database on time instead of simply the last 1000 entries.

EDIT: $+ between time. and * was kind of obsolete :P
Posted By: RusselB Re: hash table question - 28/08/10 06:10 PM
As this is untested, I recommend that you backup your hash table entries before trying this.

Usage is /purge

It should, determine the oldest time entry in the current hash table, then delete from the table those entries that match.

Code:
alias purge {
  var %a = 1, %b = $hget(seen,0).item, %oldest.time
  while %a <= %b {
    if (time.* iswm $hget(seen,%a).item) {
      if !%oldest.time || (%oldest.time > $hget(seen,%a).data) {
        %oldest.time = $v2
      }
    }
    inc %a
  }
  while $hfind(seen,%oldest.time,0,w).data {
    var %nick = $hget(seen,$hfind(seen,%oldest.time,0,w).data).item
    %nick = $gettok(%nick,2,46)
    .hdel -w seen $+(*.,%nick)
  }
}


If this works as I think, then you'll be able to use it to purge the oldest data when you want and/or have it called automatically if the number of entries in the table exceeds a certain level.
Posted By: DJ_Sol Re: hash table question - 28/08/10 08:17 PM
Personally I would store all that information in one slot.

hadd table seen.$nick $event $chan $ctime $network
Now you can use $gettok to grab the data you want from each entry. Space isn't the best delimiter IMO I just used it here as a basic example.

If you want to delete the last one I would add the integer to the item name, as I showed above. If you want to keep them as seperate entries then I would make a table for each one.

hadd action $nick $event
hadd channel $nick $chan
hadd time $nick $ctime
hadd seen $nick $network

Then a table that listed the nicks in order of appearance like I showed you above. That would be your master list.

hadd master $calc($hget(master,0).item + 1) $nick
( Stored as $hget(master,1) = $nick )

If you wanted the last nickname, you find the last nick in this list then use that nick to reference the entries in the other tables.

$hget(master,$hget(master,0).item) = last nickname entered.

The way you have it set up seems to messy to me.
Posted By: sparta Re: hash table question - 29/08/10 05:04 PM
I did change the code a bit and i using the line:

hadd seen $+($nick,|,$event,|,$chan,|,$network,|,$ctime)

But i still cant get it to delete the oldest post. Been testing a bit with the code examples i was given here, and no luck with them. so somone that have any other idea how to deal with this?

//echo -a -> $gettok($hget(seen,N).item,5,124)

return the time to me.
Posted By: DJ_Sol Re: hash table question - 29/08/10 06:53 PM
I told you how to number them and then delete them.

You have to k eep track of the order in a hash table. The item number doesn't get saved in order. Do not store the data in the item name, store it in the data section.

/hadd seen $nick $+($event,|,$chan,|,$network,|,$ctime)

I suggested you add an integer to the item name so you know the order. You could evaluate the time and find the latest time but that would take a lot of parsing. When you add the entry, simply include the number. Since it will be the last item entered, the number would be the total of items in the table plus 1.

/hadd seen $+($calc($hget(seen,0).item + 1),.,$nick) $+($event,|,$chan,|,$network,|,$ctime)

This will be stored as 1.Nickname event|chan|network|ctime.

To delete the last entry, you could use this:

/hdel -w seen $+($hget(seen,0).item,.*)

If you wanted to delete the last 5...

Code:
var %total = $hget(seen,0).item, %last5 = $calc(%total - 5)
while (%last5 <= %total) {
hdel -w seen $+(%last5,.*)
inc %last5
}


This code and idea wouldn't work well if you wanted to remove the 25th entry in a list of 200. It will only work successfully if you are removing the last entries of the list. Since that is what you specifically asked for, this is the simplest solution I can think of.

Also, I wrote this here without testing. Let me know if you have issues.
© mIRC Discussion Forums