<p>In a machine with AIX without <code>PERL</code> I need to filter records that will be considered duplicated if they have the same id and if they were registered between a period of four hours. </p>

<p>I implemented this filter using <code>AWK</code> and work pretty well but I need a solution much faster: </p>

<pre>
# Generar lista de Duplicados
awk 'BEGIN {
FS="," 
}
/OK/ { 
    old[$8] = f[$8];
    f[$8] = mktime($4, $3, $2, $5, $6, $7); 
    x[$8]++;
}
/OK/ && x[$8]>1 && f[$8]-old[$8] 

<p>Any suggestions? Are there ways to improve the environment (preloading the file or someting like that)? </p>

<p>The input file is already sorted.</p>

<p>With the corrections suggested by <a href="https://stackoverflow.com/questions/6475/faster-way-to-find-duplicates-conditioned-by-time#6869">jj33</a> I made a new version with better treatment of dates, still maintaining a low profile for incorporating more operations: </p>


awk 'BEGIN {
    FS=","; 
    SECSPERMINUTE=60;
    SECSPERHOUR=3600;
    SECSPERDAY=86400;
    split("0 31 59 90 120 151 181 212 243 273 304 334", DAYSTOMONTH, " ");
    split("0 366 731 1096 1461 1827 2192 2557 2922 3288 3653 4018 4383 4749 5114 5479 5844 6210 6575 6940 7305", DAYSTOYEAR, " ");
}
/OK/ { 
    old[$8] = f[$8];
    f[$8] = mktime($4, $3, $2, $5, $6, $7); 
    x[$8]++;
}
/OK/ && x[$8]>1 && f[$8]-old[$8]  2 ) && ( ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0) ) ) {
        d2m = d2m + 1;
    }
    d2y = DAYSTOYEAR[ y - 1999 ];
    return ss + (mm*SECSPERMINUTE) + (hh*SECSPEROUR) + (d*SECSPERDAY) + (d2m*SECSPERDAY) + (d2y*SECSPERDAY);
}
'
</pre>

[{'answer_id': 6813, 'author': 'David', 'author_id': 381, 'author_profile': 'https://Stackoverflow.com/users/381', 'pm_score': 1, 'selected': False, 'text': '<p>If your data file contains all your records (i.e. it includes records that do not have dupicate ids within the file) you could pre-process it and produce a file that only contains records that have duplicate (ids).</p>\n\n<p>If this is the case that would reduce the size of file you need to process with your AWK program.</p>\n'}, {'answer_id': 6869, 'author': 'jj33', 'author_id': 430, 'author_profile': 'https://Stackoverflow.com/users/430', 'pm_score': 1, 'selected': False, 'text': '<p>How is the input file sorted?  Like, cat file|sort, or sorted via a single specific field, or multiple fields?  If multiple fields, what fields and what order?  It appears the hour fields are a 24 hour clock, not 12, right?  Are all the date/time fields zero-padded (would 9am be "9" or "09"?)</p>\n\n<p>Without taking into account performance it looks like your code has problems with month boundaries since it assumes all months are 30 days long.  Take the two dates 2008-05-31/12:00:00 and 2008-06-01:12:00:00.  Those are 24 hours apart but your code produces the same time code for both (63339969600)</p>\n'}, {'answer_id': 7018, 'author': 'jj33', 'author_id': 430, 'author_profile': 'https://Stackoverflow.com/users/430', 'pm_score': 1, 'selected': False, 'text': '<p>I think you would need to consider leap years.  I didn\'t do the math, but I think during a leap year, with a hard code of 28 days for feb, a comparison of noon on 2/29 and noon on 3/1 would result in the same duplicate time stamp as before.  Although it looks like you didn\'t implement it like that.  They way you implemented it, I think you still have the problem but it\'s between dates on 12/31 of $leapyear and 1/1 of $leapyear+1.</p>\n\n<p>I think you might also have some collisions during time changes if your code has to handle time zones that handle them.</p>\n\n<p>The file doesn\'t really seem to be sorted in any useful way.  I\'m guessing that field $1 is some sort of status (the "OK" you\'re checking for).  So it\'s sorted by record status, then by DAY, then MONTH, YEAR, HOURS, MINUTES, SECONDS.  If it was year,month,day I think there could be some optimizations there.  Still might be but my brain\'s going in a different direction right now.</p>\n\n<p>If there are a small number of duplicate keys in proportion to total number of lines, I think your best bet is to reduce the file your awk script works over to just duplicate keys (as <a href="https://stackoverflow.com/questions/6475/faster-way-to-find-duplicates-conditioned-by-time#6813">David said</a>).  You could also preprocess the file so the only lines present are the /OK/ lines.  I think I would do this with a pipeline where the first awk script only prints the lines with duplicate IDs and the second awk script is basically the one above but optimized to not look for /OK/ and with the knowledge that any key present is a duplicate key.</p>\n\n<p>If you know ahead of time that all or most lines will have repeated keys, it\'s probably not worth messing with.  I\'d bite the bullet and write it in C.  Tons more lines of code, much faster than the awk script.</p>\n'}, {'answer_id': 7210, 'author': 'AnotherHowie', 'author_id': 923, 'author_profile': 'https://Stackoverflow.com/users/923', 'pm_score': 1, 'selected': False, 'text': '<p>On many unixen, you can get sort to sort by a particular column, or field. So by sorting the file by the ID, and then by the date, you no longer need to keep the associative array of when you last saw each ID at all. All the context is there in the order of the file.</p>\n\n<p>On my Mac, which has GNU sort, it\'s: </p>\n\n<pre><code>sort -k 8 &lt; input.txt &gt; output.txt\n</code></pre>\n\n<p>to sort on the ID field. You can sort on a second field too, by saying (e.g) 8,3 instead, but ONLY 2 fields. So a unix-style time_t timestamp might not be a bad idea in the file - it\'s easy to sort, and saves you all those date calculations. Also, (again at least in GNU awk), there is a <a href="http://www.gnu.org/manual/gawk/html_node/Time-Functions.html" rel="nofollow noreferrer">mktime function</a> that makes the time_t for you from the components.</p>\n'}, {'answer_id': 7756, 'author': 'jj33', 'author_id': 430, 'author_profile': 'https://Stackoverflow.com/users/430', 'pm_score': 1, 'selected': False, 'text': '<p>@<a href="https://stackoverflow.com/questions/6475/faster-way-to-find-duplicates-conditioned-by-time#7210">AnotherHowie</a>, I thought the whole preprocessing could be done with sort and uniq.  The problem is that the OP\'s data seems to be comma delimited and (Solaris 8\'s) uniq doesn\'t allow you any way specify the record separator, so there wasn\'t a super clean way to do the preprocessing using standard unix tools.  I don\'t think it would be any faster so I\'m not going to look up the exact options, but you could do something like:</p>\n\n<pre><code>cut -d, -f8 &lt;infile.txt | sort | uniq -d | xargs -i grep {} infile.txt &gt;outfile.txt\n</code></pre>\n\n<p>That\'s not very good because it executes grep for every line containing a duplicate key.  You could probably massage the uniq output into a single regexp to feed to grep, but the benefit would only be known if the OP posts expected ratio of lines containing suspected duplicate keys to total lines in the file.</p>\n'}, {'answer_id': 171577, 'author': 'Randal Schwartz', 'author_id': 22483, 'author_profile': 'https://Stackoverflow.com/users/22483', 'pm_score': 2, 'selected': False, 'text': '<p>This sounds like a job for an actual database.  Even something like SQLite could probably help you reasonably well here.  The big problem I see is your definition of "within 4 hours". That\'s a sliding window problem, which means you can\'t simply quantize all the data to 4 hour segments... you have to compute all "nearby" elements for every other element separately.  Ugh.</p>\n'}]
['https://Stackoverflow.com/questions/6475', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/527/']