Count edits accounting for grace period

23

When you edit a post on SE, any further edits within a 5-minute grace period are merged into it. Given a list of times you edit a post, count the edits not in a grace period.

Say you edit at minutes [0,3,4,7,9,10,11,12]. This results in 3 edits at times [0,7,12], with the rest happening in their grace periods.

0:  [3,4]
7:  [9,10,11]
12: []
  • The first edit is at minute 0. The edits at minutes 3 and 4 are within its 5-minute grace period, and so don't count.
  • The second edit is at minute 7. The edits at minutes 9, 10, 11 are within its grace period.
  • The third edit at minute 12 is just past the edge of the 5-minute grace period starting at minute 7.

So, the output is 3.

The list of times in minutes will be an list of increasing integers. The first number will always be 0 for the initial posting, which we count as an edit.

Test cases:

[0]
[0,3,5,7]
[0,3,4,7,9,10,11,12]
[0,30,120]
[0,4,8,12,16]
[0,4,8,12,16,20]
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
[0,5,10,15,20]
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
[0,1,4,5,9,11,12,14,16,18,23,24,26,28,29,30]

Outputs:

1
2
3
3
3
3
4
5
5
6

For ease of copying, here are the inputs, outputs, and input/output pairs:

[[0], [0, 3, 5, 7], [0, 3, 4, 7, 9, 10, 11, 12], [0, 30, 120], [0, 4, 8, 12, 16], [0, 4, 8, 12, 16, 20], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [0, 5, 10, 15, 20], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [0, 1, 4, 5, 9, 11, 12, 14, 16, 18, 23, 24, 26, 28, 29, 30]]
[1, 2, 3, 3, 3, 3, 4, 5, 5, 6]
[([0], 1), ([0, 3, 5, 7], 2), ([0, 3, 4, 7, 9, 10, 11, 12], 3), ([0, 30, 120], 3), ([0, 4, 8, 12, 16], 3), ([0, 4, 8, 12, 16, 20], 3), ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], 4), ([0, 5, 10, 15, 20], 5), ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], 5), ([0, 1, 4, 5, 9, 11, 12, 14, 16, 18, 23, 24, 26, 28, 29, 30], 6)]

Leaderboard:

var QUESTION_ID=141949,OVERRIDE_USER=20260;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/141949/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

xnor

Posted 2017-09-07T03:53:58.983

Reputation: 115 687

Although it's really annoying if your edit doesn't make the grace period, because then you have to use your new grace period to make it look as if you meant to edit it that way all along... – Neil – 2017-09-14T00:33:50.660

Answers

20

JavaScript, 36 bytes

f=$=>$>f&&1+f($.filter(b=>b-$[0]>4))

Try it online!

How it works

In each recursive call we delete all elements from the array which are more than 4 minutes distant from the first element.
There is a little trick with variable name $. The check $>f firstly converts the array to a string and then compare it to the string representation of the function f and then compares them lexicographically. The first character of stringified array is a digit and therefore only one-char variable name whose ascii index is smaller than indices of all digits is $. Replacing $ with any other variable name will always return false.

user72349

Posted 2017-09-07T03:53:58.983

Reputation:

3I love this site because of answers like these. – Cristian Lupascu – 2017-09-07T06:44:56.920

1Very nice trick! – Arnauld – 2017-09-07T09:09:04.713

1Oh, now, that is a great trick! – Shaggy – 2017-09-07T09:51:26.353

8

Mathematica, 46 40 37 33 bytes

(i=1;j=0;#-j<5||(i++;j=#)&/@#;i)&

Explanation

i=1;j=0

Set i to 1 and j to 0.

... /@#

Map onto all elements of the input...

#-j<5||(i++;j=#)&

If (element) - j < 5 is false, then increment i and set j to the element (short-circuit evaluation).

;i

Output i.

JungHwan Min

Posted 2017-09-07T03:53:58.983

Reputation: 13 290

5

Python 2, 58 bytes

a=input()
x=[0]
for k in a:x+=[k]*(k-x[-1]>4)
print len(x)

Try it online!

  • Saved 2 bytes thanks to @Mr. Xcoder.

49 bytes

f=lambda a:a>[]and-~f([x for x in a if x-a[0]>4])

Using the recursive method shown in @ThePirateBay's solution.

  • Saved a byte thanks to @Mr. Xcoder.
  • Saved 2 bytes thanks to @Halvard Hummel.

Try it online!

miles

Posted 2017-09-07T03:53:58.983

Reputation: 15 654

and 1+f(...) can be replaced by and-~f(...) for 49 bytes – Mr. Xcoder – 2017-09-07T07:27:39.717

@Mr.Xcoder Oh, can't forget all those bitwise tricks. – miles – 2017-09-07T07:37:28.793

x=a[:1] is equivalent to x=[0], since the question explicitly states that the first element is always 0 (62 bytes) – Mr. Xcoder – 2017-09-07T08:01:23.920

147 bytes recursive – Halvard Hummel – 2017-09-07T08:42:19.953

5

Husk, 8 bytes

Γ(→₀f>+4

Try it online!

Explanation

Γ(→₀f>+4  Implicit input, a list of numbers.
Γ(        Deconstruct into head n and tail x (if empty, return 0).
    f>+4  Keep those elements of x that are greater than n+4.
   ₀      Call main function recursively on the result.
  →       Increment.

Zgarb

Posted 2017-09-07T03:53:58.983

Reputation: 39 083

3

J, 20 bytes

[:#(,}.~5>(-{.))/@|.

Try it online!

Explanation

[:#(,}.~5>(-{.))/@|.  Input: array A
                  |.  Reverse
                /@    Reduce from right-to-left
            {.          Head of RHS
           -            Subtract with LHS
        5>              Less than 5
     }.~                Drop that many from
    ,                   Join
[:#                   Length

miles

Posted 2017-09-07T03:53:58.983

Reputation: 15 654

3

MATLAB, 34 bytes

@(x)nnz(uniquetol(x+1,4/max(x+1)))

Anonymous function that inputs an array and outputs a number.

This uses the uniquetol function, specifically its form y = uniquetol(x, t), which gives y containing unique elements of x with tolerance t. In doing so, the function seems to follow a "lazy" approach: sort x, pick its first entry, and keep skipping entries for as long as they are within tolerance of the latest picked entry. That is exactly what is needed here.

The uniquetol function automatically scales the specified tolerance by the maximum absolute value in a. This is why we need the division here. x+1 is used instead of x to avoid division by 0.

Verification of test cases:

>> f = @(x)nnz(uniquetol(x+1,4/max(x+1)));
>> inputs = {...
       [0] ...
       [0,3,5,7] ...
       [0,3,4,7,9,10,11,12] ...
       [0,30,120] ...
       [0,4,8,12,16] ...
       [0,4,8,12,16,20] ...
       [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19] ...
       [0,5,10,15,20] ...
       [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20] ...
       [0,1,4,5,9,11,12,14,16,18,23,24,26,28,29,30] ...
   };
>> outputs = cellfun(f, inputs)
outputs =
     1     2     3     3     3     3     4     5     5     6

Luis Mendo

Posted 2017-09-07T03:53:58.983

Reputation: 87 464

1TIL about uniquetol... Introduced in R2015a. I have R2014b :( Nice answer :) – Stewie Griffin – 2017-09-07T12:59:25.743

@Stewie I knew it existed, but I think this is the first time I use it – Luis Mendo – 2017-09-07T14:53:50.603

2

Haskell, 31 30 bytes

f(x:y)=f[z|z<-y,z-4>x]+1
f x=0

Try it online!

Saved 1 byte thanks to Zgarb

Cristian Lupascu

Posted 2017-09-07T03:53:58.983

Reputation: 8 369

z-4>x should save a byte. – Zgarb – 2017-09-07T07:29:20.677

@Zgarb What was I thinking??? Thanks! :) – Cristian Lupascu – 2017-09-07T08:29:18.490

2

05AB1E, 20 19 18 15 14 11 bytes

v®y‹iy4+©\¼

Explanation:

v          # loop on input
 ®          # push register_c, start at -1
  y‹i         # if current item greater than last item
   y4+         # push new max on stack
    ©\          # push new max on register_c, and pop it from stack
     ¼           # increment counter_variable
                  # implicit print of counter_variable

Try it online!

Edit

  • -3 bytes thanks to Riley and the usage of counter_variable
  • no need for counter_variable after all
  • -3 bytes again thanks to Riley and the usage of register_c

Cyril Gandon

Posted 2017-09-07T03:53:58.983

Reputation: 199

You can use the counter variable to save 3 bytes: ¼4¹vDy‹i¼y4+}}¾

– Riley – 2017-09-07T15:03:33.860

oooooh, there is a counter variable, that's handy! Thank you!! – Cyril Gandon – 2017-09-07T15:29:08.610

1

11 bytes: v®y‹iy4+©\¼

– Riley – 2017-09-07T16:20:40.913

2

Husk, 6 bytes

Lüo<+5

Try it online!

  o<+5        a function that takes two arguments and checks if
              the second is less than the the first plus 5
 ü            remove equal elements from the input list using the above
              function as the equality test
L             return the length of the remaining list

nimi

Posted 2017-09-07T03:53:58.983

Reputation: 34 639

Whoa, I didn't realize ü works like that! That's very handy. – Zgarb – 2017-09-07T19:45:52.150

@Zgarb: I first tried ġ but it doesn't work, whereas Haskell's groupBy works: length.groupBy((>).(+5)). Then I found ü which also leads to a shorter Haskell equivalent: nubBy. – nimi – 2017-09-07T19:50:38.707

1

Pyth, 14 bytes

L&lbhyfg-Thb5b

This is a recursive function. Call it with y[0 1 2 3 4 5 6 7 8), where [...) is your list.

Alternatively, Try it here! or Verify all the test cases.


Explanation

This is roughly equivalent to the Python solution. A translation would give the following results:

def y(b):
 return (len(b) and y(filter(lambda T:T>=b[0]+5,b)) + 1)

Code Breakdown

L&lbhyfg-Thb5b   - Function called y that accepts a list parameter b.

L                - Define the function.
  lb             - The length of b...
 &               - ... Logical AND ...
    h            - Increment by 1.
     y           - The result given by calling the function recursively on the following:
      f      b     - b filtered...
        -Thb       - ... For the elements whose difference compared to the first element...
       g    5      - ... Is greater than or equal to 5.

Mr. Xcoder

Posted 2017-09-07T03:53:58.983

Reputation: 39 774

I am trying to find a workaround with .U. Suggestions are welcome – Mr. Xcoder – 2017-09-07T08:14:38.150

1

05AB1E, 14 bytes

æʒ¬s¥4›Ps_*}θg

Try it online!

Erik the Outgolfer

Posted 2017-09-07T03:53:58.983

Reputation: 38 134

That's insane, æ for superset, that's a great trick! – Cyril Gandon – 2017-09-07T14:22:32.093

@CyrilGandon æ means "powerset". – Erik the Outgolfer – 2017-09-07T14:24:40.660

1

Java 8, 78 61 60 59 56 bytes

Port of @JungHwanMin's answer

a->{int i=0;for(int l:a)if(l-a[i]>4)a[++i]=l;return-~i;}

Try it online!

Roberto Graham

Posted 2017-09-07T03:53:58.983

Reputation: 1 305

You can save 4 bytes like this: a->{int i=0;for(int l:a)if(l-a[i]>4)a[++i]=l;return-~i;}

– Kevin Cruijssen – 2017-09-07T13:35:30.463

1

MATL, 13 12 bytes

`ttX<4+>)t}@

Try it online! Or verify all test cases.

Explanation

`        % Do..while
  t      %   Duplicate. Takes input (implicitly) the first time
  tX<    %   Duplicate and get minimum, i.e the first entry
  4+     %   Add 4
  >      %   Greater than? Element-wise
  )      %   Keep entries that fulfill that
  t      %   Duplicate. This is used as loop condition
}        % Finally (execute at the end of the loop)
  @      %   Push number of iterations. This is the output
         % End (implicit). A new iteration is run if top of the stack is truthy

Luis Mendo

Posted 2017-09-07T03:53:58.983

Reputation: 87 464

1

C# .NET, 63 bytes

a=>{int e=0;foreach(int l in a)if(l-a[e]>4)a[++e]=l;return-~e;}

Explanation:

Try it here.

a=>{                   // Method with integer-array parameter and integer return-type
  int e=0;             //  Amount of edits (starting at 0)
  foreach(int l in a)  //  Loop over the input-array
    if(l-a[e]>4)       //   If the current value minus the current edit is larger than 4:
      a[++e]=l;        //    Raise the edit-count by 1 first,
                       //    and set the current value to this next current edit
                       //  End of loop (implicit / single-line body)
  return-~e;           //  Return the amount of edits + 1
}                      // End of method

Kevin Cruijssen

Posted 2017-09-07T03:53:58.983

Reputation: 67 575

0

Jelly, 11 bytes

+4Ḣ<x@µÐĿL’

Try it online!

Explanation

+4Ḣ<x@µÐĿL’  Input: array A
      µÐĿ    Repeat until the results converge
+4             Add 4
  Ḣ            Head
   <           Greater than
    x@         Copy only the true values
         L   Length
          ’  Decrement

12 bytes

;I4<1;x@;ð/L

Try it online!

Explanation

;I4<1;x@;ð/L  Input: array A
         ð/   Reduce A from left-to-right using
;               Concatenate
 I              Increment
  4<            Greater than 4
    1;          Prepend 1
      x@        Times each of
        ;       Concatenate
           L  Length

miles

Posted 2017-09-07T03:53:58.983

Reputation: 15 654

0

Perl 5, 54 bytes

52 bytes of code +2 for -ap

{$_++;$p=shift@F;1while$F[0]<$p+5&&shift@F;@F&&redo}

Try it online!

Xcali

Posted 2017-09-07T03:53:58.983

Reputation: 7 671

0

Pyth, 25 bytes

J1K5FN.+Q=-KNIg0K=hJ=K5;J

Try it here: http://pyth.herokuapp.com

Karan Elangovan

Posted 2017-09-07T03:53:58.983

Reputation: 179

Keeping it as a full program, you can get 21 bytes.

– Mr. Xcoder – 2017-09-07T08:00:10.577

0

Proton, 40 bytes

Heavily inspired by the Python solution.

f=a=>len(a)and-~f(filter(x=>x>a[0]+4,a))

Try it online!

Mr. Xcoder

Posted 2017-09-07T03:53:58.983

Reputation: 39 774

0

Retina, 32 26 bytes

.+
$*11
(1+)(¶1{1,4}\1)*\b

Try it online! Explanation:

.+
$*11

Convert to unary, but add 1, because 0 is a tricky concept in Retina.

(1+)(¶1{1,4}\1)*\b

Count the number of edits, but include all the grace edits in each match.

Neil

Posted 2017-09-07T03:53:58.983

Reputation: 95 035

0

Ly, 29 bytes

&nr5+sp[[lL[pp2$]p5+sp>`<]]>`

Try it online!

It took a long time to get here.

LyricLy

Posted 2017-09-07T03:53:58.983

Reputation: 3 313

0

Kotlin, 52 bytes

Posting as a function, if this is not acceptable I will change it to a method

Submission

{var x=it[0]
var o=1
it.map{if(it>x+4){o++
x=it}}
o}

Beautified

{
    // Last counted edit
    var x=it[0]
    // Current edit total
    var o = 1
    // For each edit
    it.map{
        // If it was 5 or more minutes ago
        if (it>x+4) {
            // Increase edit count
            o++
            // Make it the last counted edit
            x=it
        }
    }
    // Return the edit count
    o
}

Test

var r:(IntArray)->Int=
{var x=it[0]
var o=1
it.map{if(it>x+4){o++
x=it}}
o}

fun main(args: Array<String>) {
    println(r(intArrayOf(0)))
    println(r(intArrayOf(0,3,5,7)))
    println(r(intArrayOf(0,3,4,7,9,10,11,12)))
    println(r(intArrayOf(0,30,120)))
    println(r(intArrayOf(0,4,8,12,16)))
    println(r(intArrayOf(0,4,8,12,16,20)))
    println(r(intArrayOf(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)))
    println(r(intArrayOf(0,5,10,15,20)))
    println(r(intArrayOf(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)))
    println(r(intArrayOf(0,1,4,5,9,11,12,14,16,18,23,24,26,28,29,30)))
}

TryItOnline

jrtapsell

Posted 2017-09-07T03:53:58.983

Reputation: 915

0

PowerShell, 74 bytes

for($x,$y=$args[0];$y;$x,$y=$y){if($l-le$x-5){$i++;$l=$x}}$i+1+($l-le$x-5)

Iterative solution. Lengthy because of fenceposting on the for loop requiring an additional check on the end. Golfing suggestions welcome.

We take input $args[0] as a literal array, peel off the first element into $x and the remaining into $y. Then, so long as there are elements still in $y, we loop.

Each iteration, we check whether the current timestamp $x is 5 or more away from the $last edit timestamp. If so, we increment our counter $i++ and set our timestamp to be current. Then, on the iteration of the loop, we peel off the next element into $x and leave the remaining in $y.

Once we're out of the loop, we output $i, plus 1 for the initial edit, plus whether the final timestamp is more than five away from the last edit (with the Boolean value implicitly cast to integer). That result is left on the pipeline and output is implicit.

Try it online!

AdmBorkBork

Posted 2017-09-07T03:53:58.983

Reputation: 41 581

0

R, 52 bytes

function(l){while(sum(l|1)){l=l[l-l[1]>=5]
F=F+1}
F}

Try it online!

Simple anonymous function that iteratively removes elements from the list that are less than 5 away from the first element until the list is empty, then returns the counter.

Giuseppe

Posted 2017-09-07T03:53:58.983

Reputation: 21 077

0

Clojure, 53 bytes

#(count(set(reductions(fn[r v](if(<(- v r)5)r v))%)))

This keeps track of the "edit starting times", and then returns their distinct count.

NikoNyrh

Posted 2017-09-07T03:53:58.983

Reputation: 2 361

0

Japt, 14 bytes

Ê©1+ßUf_aUg)>4

Try it


Explanation

Implicit input of array U

Ê

Get the length of U.

©

Logical AND (&&) - only execute the following if Ê is truthy (non-zero).

ß

Recursive call.

Uf_

Filter (f) U by passing each element through a function.

aUg

Get the difference (a) between the current element and the first element (g) of U.

>4

Greater than 4?

1+

Add 1.

Implicit output of resulting integer.

Shaggy

Posted 2017-09-07T03:53:58.983

Reputation: 24 623