10
\$\begingroup\$

This a simple question.

The start day is a Saturday and let the input be a non-negative number x.

The output should be the number of weekdays (Mon-Fri) in the next x days inclusive.

For example, if x = 3 then the output should be 2. For x from 0 onwards the output should be:

0,0,1,2,3,4,5,5,5,6,7,8,9,10,10,10,11,...

—-—

Now I am regretting not having asked the question for a user specified day of the week instead of just Saturday. It’s too late to change the question now and a new question would probably be marked as a duplicate. If anyone wanted to add an answer for this extension, I would love to see it.

\$\endgroup\$
  • 6
    \$\begingroup\$ I found the title on this really confusing. I assumed it meant "how many weekdays until Saturday" which should never exceed five. But actually you're asking something completely different. I suggest revising the title to "how many weekdays" \$\endgroup\$ – Level River St Jun 28 at 13:29

21 Answers 21

13
\$\begingroup\$

Python 2, 18 bytes

lambda x:x*6/7-x/7

Try it online!

Found by brute-forcing. x*6/7 counts non-Sundays, and -x/7 subtracts the number of Saturdays.

all          x       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 ...

all - Sun  = x*6/7   0  0  1  2  3  4  5  6  6  7  8  9 10 11 12 12 13 ...
Sat        = x/7     0  0  0  0  0  0  0  1  1  1  1  1  1  1  2  2  2 ...
all - Sun - Sat      0  0  1  2  3  4  5  5  5  6  7  8  9 10 10 10 11 ...

Brute-forcing suggests that this is the unique arithmetical solution of this length or shorter, subject to some limitations like not using parens, using only single-digit constants, and not having too-large intermediate results.


19 bytes

lambda x:x-x/7+-x/7

Try it online!

Found by brute-forcing. But, it has a nice interpretation. x counts all x days. Then -x/7 subtracts the number of Sundays in those x days, and +-x/7 subtracts the number of Saturdays. Note that there's a difference in Python between subtracting x/7 and adding -x/7 aka (-x)/7, because floor-div is not symmetric around zero since it always round down.

all =   x        0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 ... 
Sun =   x/7      0  0  0  0  0  0  0  1  1  1  1  1  1  1  2  2  2 ...
Sat = -(-x/7)    0  1  1  1  1  1  1  1  2  2  2  2  2  2  2  3  3 ...

all - Sun - Sat  0  0  1  2  3  4  5  5  5  6  7  8  9 10 10 10 11 ...

20 bytes

lambda x:x*5/7+x%7/4

Try it online!

I found this by hand, noting that f(x) increases asymptotically with slope 5/7 and seeing that the difference to x*5/7 (with floor-division) has a nice period-7 form.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ What does +- do? \$\endgroup\$ – Anush Jun 28 at 7:17
  • 1
    \$\begingroup\$ @Anush The +-x/7 adds the term -x/7 AKA (-x)/7, which is different from the earlier term -x/7 which subtracts x/7, since Python's mod isn't symmetric around zero. \$\endgroup\$ – xnor Jun 28 at 7:19
  • \$\begingroup\$ I wonder what you can do in Python 3. \$\endgroup\$ – Anush Jun 28 at 7:27
  • \$\begingroup\$ @Anush That's an interesting question. Since the / will need to be //, it might be that something with % for mod becomes better. I'll see what the brute-forcing gives. \$\endgroup\$ – xnor Jun 28 at 7:29
  • 1
    \$\begingroup\$ @Anush Maybe? I don't see an obvious extension, but there's probably some way to incorporate an offset corresponding to the starting day. \$\endgroup\$ – xnor Jul 1 at 9:22
8
\$\begingroup\$

APL (Dyalog Unicode), 7 bytes

+/2≤7|⍳

Try it online!

1-based range is a big win here.

How it works

+/2≤7|⍳
      ⍳  ⍝ 1-based range
    7|   ⍝ modulo 7; 1 2 3 4 5 6 0 ...
  2≤     ⍝ is at least 2; 0 1 1 1 1 1 0 ...
+/       ⍝ sum the booleans

For the bonus question (let the user provide the day of the week to start):

APL (Dyalog Unicode), 11 bytes

+/⎕⍴⎕⌽7↑5⍴1

Try it online!

We don't need any fancy arithmetic. Just create a bit vector, rotate it to match the requested day of week to start with, cycle it and count ones (i.e. sum).

Accepts Sun, Mon, ..., Sat as the number 0, 1, ..., 6 as the first input, and the number of days as the second (both from stdin). (It actually works for any integers (for the first input) and gives the result as if it was modulo 7.)

How it works

+/⎕⍴⎕⌽7↑5⍴1
      7↑5⍴1  ⍝ 1 repeated 5 times and then overtaken to length 7
             ⍝ i.e. 1 1 1 1 1 0 0
    ⎕⌽  ⍝ Take the starting weekday and rotate ^ that many units to the left
  ⎕⍴    ⍝ Take the number of days and cycle ^ to that length
+/      ⍝ Sum
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thank you for the bonus answer! \$\endgroup\$ – Anush Jun 29 at 5:50
7
\$\begingroup\$

05AB1E, 8 6 bytes

Ý7%1›O

Try it online!

Very similar to the APL answer

Explained

Ý    | Generate a list between 0 and input 
7%   | Mod each number by 7
1›   | Determine if each number is greater than 1
O    | Summate the list and output it
| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

JavaScript (ES6), 16 bytes

n=>n*20/7+n%7>>2

Try it online!

How?

The expression \$\lfloor 5n/7\rfloor\$ gives the correct answer when \$n\bmod 7\$ is less than or equal to \$3\$ but is off by \$1\$ otherwise.

 n           | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16
-------------+---+---+---+---+---+---+---+---+---+---+----+----+----+----+----+----+----
 floor(5n/7) | 0 | 0 | 1 | 2 | 2 | 3 | 4 | 5 | 5 | 6 |  7 |  7 |  8 |  9 | 10 | 10 | 11
 expected    | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 5 | 5 | 6 |  7 |  8 |  9 | 10 | 10 | 10 | 11
 difference  | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |  0 |  1 |  1 |  1 |  0 |  0 |  0
 n mod 7     | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 1 | 2 |  3 |  4 |  5 |  6 |  0 |  1 |  2

This can be adjusted with:

$$f(n)= \left\lfloor\frac{5n}{7}\right\rfloor+\left\lfloor\frac{n\bmod 7}{4}\right\rfloor$$

which may also be expressed as:

$$f(n)= \left\lfloor\frac{20n/7+(n\bmod 7)}{4}\right\rfloor$$


JavaScript (Node.js), 15 bytes

In order to use @xnor's formula without adding explicit floor operations, we have to work with BigInts. So this version expects a BigInt as input.

n=>n*6n/7n-n/7n

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Does 20/7*n run the risk of a floating-point rounding error in a way n*20/7 would not? \$\endgroup\$ – Neil Jun 28 at 10:22
  • \$\begingroup\$ @Neil I'm almost certain it's safe in this case. But since you're right in the general case, I've updated it anyway. \$\endgroup\$ – Arnauld Jun 28 at 10:35
  • \$\begingroup\$ I really like this answer because I can read it and it comes with math. More languages have integer division than I had expected! \$\endgroup\$ – Anush Jun 29 at 6:09
  • \$\begingroup\$ @Anush Just to clarify, JS doesn't have integer division (which is why I use a right-shift instead) unless we work with BigInts. I've added a port of xnor's answer to illustrate that. \$\endgroup\$ – Arnauld Jun 29 at 7:04
  • \$\begingroup\$ How come 20/7 doesn't return a float in that case? Are you assuming BigInts there too? \$\endgroup\$ – Anush Jun 29 at 8:28
3
\$\begingroup\$

Japt, 7 bytes

Port of Bubbler's APL solution so be sure to +1 them, too.

õu7 x¨2

Try it - Includes all test cases

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

bc, 29 bytes

define f(n){return n*6/7-n/7}

Try it online!

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Jelly, 6 bytes

R%7>1S

Try it online!

Interestingly equal-length in all regards to Lyxal's 05AB1E answer, so I've copy-pasted the explanation, swapping out the commands.

R    | Generate a list between 0 and input 
%7   | Mod each number by 7
>1   | Determine if each number is greater than 1
S    | Summate the list and output it
| improve this answer | |
\$\endgroup\$
  • 3
    \$\begingroup\$ An all-ASCII Jelly answer, isn't that world first? :P \$\endgroup\$ – Sok Jun 29 at 15:17
2
\$\begingroup\$

C (gcc), 18 bytes

f(n){n=n*6/7-n/7;}

Try it online!

Port of xnor's formula from his Python 2 answer.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Java, 12 bytes

x->x*6/7-x/7
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

perl -Minteger -lp, 14 bytes

$_=$_*6/7-$_/7

Try it online!

Uses the same algorithm as the Python 2 solution from @xnor. The -Minteger switch makes perl use integer division.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

x86-16 machine code, 16 bytes

33 DB       XOR  BX, BX         ; clear BX sum 
        MLOOP: 
E3 0B       JCXZ DONE           ; handle x = 0 
8A C1       MOV  AL, CL         ; loop counter to AL
D4 07       AAM  7              ; AL = AL mod 7 
3C 01       CMP  AL, 1          ; AL <= 1 ? 
7E 01       JLE  IS_WEEKEND     ; if so, is a weekend
43          INC  BX             ; otherwise increment count 
        IS_WEEKEND: 
E2 F3       LOOP MLOOP          ; loop until 0
        DONE: 
C3          RET                 ; return to caller

Callable function, input in CL (unsigned byte) output to BX.

enter image description here

Or 22 bytes to operate on 16 bit unsigned WORD in CX:

33 DB       XOR  BX, BX         ; clear BX sum 
        MLOOP: 
E3 11       JCXZ DONE           ; handle x = 0 
8B C1       MOV  AX, CX
33 D2       XOR  DX, DX         ; clear DX (high word of quotient)
BF 0007     MOV  DI, 7          ; set up WORD divisor
F7 F7       DIV  DI             ; DX = DX:AX mod DI
80 FA 01    CMP  DL, 1          ; DL <= 1 ?
7E 01       JLE  IS_WEEKEND     ; if so, is a weekend 
43          INC  BX             ; otherwise increment count 
        IS_WEEKEND: 
E2 ED       LOOP MLOOP 
        DONE: 
C3          RET                 ; return to caller
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Retina 0.8.2, 22 bytes

.+
$*
.(.{0,5}).?
$1
.

Try it online! Link includes test cases. Explanation:

.+
$*

Convert to unary.

.(.{0,5}).?

For each week, match Sunday, then up to five weekdays, then optionally match Saturday.

$1

Keep just the weekdays.

.

Count the resulting weekdays.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Charcoal, 10 bytes

IΣ…⪫00×⁵1N

Try it online! Link is to verbose version of code. This is actually 3 bytes shorter than trying to calculate the result arithmetically. Explanation:

        1   Literal string `1`
      ×⁵    Repeated 5 times i.e. `11111`
    00      Literal string `00`
   ⪫        Join its characters giving `0111110`
  …      N  Cyclically extend to the input number of days
 Σ          Sum the digits
I           Cast to string
            Implicitly print
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Pyth, 8 bytes

lf<1%T7S

Try it online!

Port of Bubbler's APL solution.

Explanation

lf<1%T7S
l         : length of
 f        : filter on
       S  : 1-based range to input
  <1%T7   : where mod 7 is greater than 1
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

AWK, 29 bytes

{print int($0*6/7)-int($0/7)}

Try it online!

Port of @xnor's Python 2 answer.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Befunge-93, 12 bytes

&:6*7/\7/-.@

Try it online!

Another port of xnor's algorithm.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Pyth, 7 bytes

sm<1%d7

Try it online!

Port of Lyxal's 05AB1E answer.

sm<1%d7   
 m        For each number from 0-input:
    %d7     Mod 7
  <1        Greater than 1
s         Take the sum, implicit print
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Io, 44 bytes

It seems like ranging is too costly here.

f :=method(x,if(x>0,if(x%7>1,1,0)+f(x-1),0))

Try it online!

Io, 46 bytes

method(x,Range 0 to(x)map(i,if(i%7>1,1,0))sum)

Try it online!

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

brainfuck, 142 bytes

(Due to number-wrapping problems) The maximum supported input is 255.

>,[[>+>+<<-]>[-<+>]<->>>+++++++<[>->+<[>]>[<+>-]<<[<]>-]>[-]>>+<[<<<+>>>>[-<<<<[-]>+>>>]<<<<[->>+<<]>[->>>+<<<]>>>-<-]>[-]<<[-<<<<+>>>>]<<<]<.

Try it online!

If you are not sure whether this output is correct, try this link.

Explanation

>,

Read input

[

While the input is nonzero:

[>+>+<<-]>[-<+>]

>x 0 0 -> x 0 >x

<->>>+++++++<[>->+<[>]>[<+>-]<<[<]>-]>[-]

Modulo by 7

>>+<[<<<+>>>>[-<<<<[-]>+>>>]<<<<[->>+<<]>[->>>+<<<]>>>-<-]>[-]<<

Check if this number is greater than 1

[-<<<<+>>>>]<<<

Add it to the accumulator (at the first item of the tape)

]

End while

<.

Move to the accumulator, print the value.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Julia, 143 Bytes

function weekdays(days)
    r = mod(days, 7)
    if r <= 2 r=0
    else r -= 2
    end
    wd::Int64 = floor(days/7)
    return(5 * wd + r)
end

Try it online!

To use a custom start date, I add an offset argument, and days += offset at the start of the function

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Golfed, 89 bytes \$\endgroup\$ – Lyxal Jul 5 at 4:40
  • 1
    \$\begingroup\$ Welcome to the site! These tips for golfing in Julia might be helpful. Also note that you should avoid using spaces (where possible) to minimise your byte count. \$\endgroup\$ – Dingus Jul 5 at 10:04
0
\$\begingroup\$

Keg, 10 bytes

0&1ɧ⑷7%1>⑼

Try it online!

Total not a port of Lyxal's my 05AB1E answer... (spoiler, it is). ;P

Explained

0&1ɧ⑷7%1>⑼
0&              # Store 0 in the register, as this will be used to keep track of the number of weekdays
  1ɧ            # Create a range between 1 and the implicit input
    ⑷           # Map the following to each item in the stack:
      7%1>⑼     # Increment the register by whether or not ((item % 7) > 1)
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.