Advent of Code 2018 Day 4 - Pythonic Sleepy Guards
Introduction
I'm using Advent of Code 2018 to learn Python better, interested in the new type support for Python 3.7, I decided to go with that.
Here is my solution to Advent of Code Day 4, both part 1 and 2. I'm returning the answers for both part 1 and 2 as a tuple.
Problem Description
The problem essentially boils down to: Given a timestamped unsorted list of events of guards beginning their shift, waking up and falling asleep, determine the following:
Part 1: Which guard is asleep the most and on which minute is that guard mostly asleep? Return guard id multiplied by the minute number.
Part 2: Which guard is most frequently asleep on the same minute? Again, return guard id multiplied by the minute number.
For full problem description, please see Advent of Code Day 4
Concerns
I'm a big fan of Java 8 Stream API and C# Linq, I kind of expected Python to be more like that. I'm not sure if the nested function calls like sorted(list(...))
or len(list(...))
are "Pythonic". Likewise, it feels like I should be able to use some reducer-like function calls instead of imperatively looping through stuff to find the most common sleeper of some kind. Or is the way I have written this code the Python way to do it?
Code
from dataclasses import dataclass
from datetime import datetime
from days import read_file
from enum import Enum
from collections import defaultdict, namedtuple
from statistics import mode
import statistics
import operator
import re
class EventType(Enum):
STARTS_SHIFT = 1
FALLS_ASLEEP = 2
WAKES_UP = 3
@dataclass
class Event:
time: datetime
guard: int
event: EventType
@dataclass
class GuardSleep:
sleep_total: int
last_sleep: int
sleeps: list
def add_sleeps(self, minute):
for i in range(self.last_sleep, minute):
self.sleeps.append(i)
def get_guard(line: str):
if "Guard" in line:
guard_id = re.search("Guard #(\d+)", line)
return int(guard_id.group(1))
return -1
def event_type(line):
if "begins shift" in line:
return EventType.STARTS_SHIFT
if "falls asleep" in line:
return EventType.FALLS_ASLEEP
if "wakes up" in line:
return EventType.WAKES_UP
raise Exception("Unknown line: " + line)
def day4() -> (int, int):
events = sorted(list(Event(datetime.strptime(line[1:17], "%Y-%m-%d %H:%M"), get_guard(line), event_type(line)) for line in read_file(4)), key=operator.attrgetter("time"))
guard = -1
guardsleep = defaultdict(lambda: GuardSleep(0, 0, ))
for event in events:
if event.guard >= 0:
guard = event.guard
if event.event == EventType.FALLS_ASLEEP:
guardsleep[guard].last_sleep = event.time.minute
if event.event == EventType.WAKES_UP:
guardsleep[guard].sleep_total += event.time.minute - guardsleep[guard].last_sleep
guardsleep[guard].add_sleeps(event.time.minute)
most_sleepy_guard_number = max(guardsleep, key=(lambda key: guardsleep[key].sleep_total))
most_sleepy_guard = guardsleep[most_sleepy_guard_number]
part1_result = most_sleepy_guard_number * mode(sorted(most_sleepy_guard.sleeps))
# Part 2
MostSleepy = namedtuple('MostCommon', ['id', 'minute', 'amount'])
most_sleepy = MostSleepy(0, 0, 0)
for k in guardsleep:
current_guard = guardsleep[k]
try:
most_common_minute = mode(sorted(current_guard.sleeps))
amount = len(list((m for m in current_guard.sleeps if m == most_common_minute)))
if amount > most_sleepy.amount:
most_sleepy = MostSleepy(k, most_common_minute, amount)
except statistics.StatisticsError:
print("No unique most common minute for " + str(k))
return part1_result, most_sleepy.id * most_sleepy.minute
if __name__ == '__main__':
print(day4())
python python-3.x programming-challenge
add a comment |
Introduction
I'm using Advent of Code 2018 to learn Python better, interested in the new type support for Python 3.7, I decided to go with that.
Here is my solution to Advent of Code Day 4, both part 1 and 2. I'm returning the answers for both part 1 and 2 as a tuple.
Problem Description
The problem essentially boils down to: Given a timestamped unsorted list of events of guards beginning their shift, waking up and falling asleep, determine the following:
Part 1: Which guard is asleep the most and on which minute is that guard mostly asleep? Return guard id multiplied by the minute number.
Part 2: Which guard is most frequently asleep on the same minute? Again, return guard id multiplied by the minute number.
For full problem description, please see Advent of Code Day 4
Concerns
I'm a big fan of Java 8 Stream API and C# Linq, I kind of expected Python to be more like that. I'm not sure if the nested function calls like sorted(list(...))
or len(list(...))
are "Pythonic". Likewise, it feels like I should be able to use some reducer-like function calls instead of imperatively looping through stuff to find the most common sleeper of some kind. Or is the way I have written this code the Python way to do it?
Code
from dataclasses import dataclass
from datetime import datetime
from days import read_file
from enum import Enum
from collections import defaultdict, namedtuple
from statistics import mode
import statistics
import operator
import re
class EventType(Enum):
STARTS_SHIFT = 1
FALLS_ASLEEP = 2
WAKES_UP = 3
@dataclass
class Event:
time: datetime
guard: int
event: EventType
@dataclass
class GuardSleep:
sleep_total: int
last_sleep: int
sleeps: list
def add_sleeps(self, minute):
for i in range(self.last_sleep, minute):
self.sleeps.append(i)
def get_guard(line: str):
if "Guard" in line:
guard_id = re.search("Guard #(\d+)", line)
return int(guard_id.group(1))
return -1
def event_type(line):
if "begins shift" in line:
return EventType.STARTS_SHIFT
if "falls asleep" in line:
return EventType.FALLS_ASLEEP
if "wakes up" in line:
return EventType.WAKES_UP
raise Exception("Unknown line: " + line)
def day4() -> (int, int):
events = sorted(list(Event(datetime.strptime(line[1:17], "%Y-%m-%d %H:%M"), get_guard(line), event_type(line)) for line in read_file(4)), key=operator.attrgetter("time"))
guard = -1
guardsleep = defaultdict(lambda: GuardSleep(0, 0, ))
for event in events:
if event.guard >= 0:
guard = event.guard
if event.event == EventType.FALLS_ASLEEP:
guardsleep[guard].last_sleep = event.time.minute
if event.event == EventType.WAKES_UP:
guardsleep[guard].sleep_total += event.time.minute - guardsleep[guard].last_sleep
guardsleep[guard].add_sleeps(event.time.minute)
most_sleepy_guard_number = max(guardsleep, key=(lambda key: guardsleep[key].sleep_total))
most_sleepy_guard = guardsleep[most_sleepy_guard_number]
part1_result = most_sleepy_guard_number * mode(sorted(most_sleepy_guard.sleeps))
# Part 2
MostSleepy = namedtuple('MostCommon', ['id', 'minute', 'amount'])
most_sleepy = MostSleepy(0, 0, 0)
for k in guardsleep:
current_guard = guardsleep[k]
try:
most_common_minute = mode(sorted(current_guard.sleeps))
amount = len(list((m for m in current_guard.sleeps if m == most_common_minute)))
if amount > most_sleepy.amount:
most_sleepy = MostSleepy(k, most_common_minute, amount)
except statistics.StatisticsError:
print("No unique most common minute for " + str(k))
return part1_result, most_sleepy.id * most_sleepy.minute
if __name__ == '__main__':
print(day4())
python python-3.x programming-challenge
add a comment |
Introduction
I'm using Advent of Code 2018 to learn Python better, interested in the new type support for Python 3.7, I decided to go with that.
Here is my solution to Advent of Code Day 4, both part 1 and 2. I'm returning the answers for both part 1 and 2 as a tuple.
Problem Description
The problem essentially boils down to: Given a timestamped unsorted list of events of guards beginning their shift, waking up and falling asleep, determine the following:
Part 1: Which guard is asleep the most and on which minute is that guard mostly asleep? Return guard id multiplied by the minute number.
Part 2: Which guard is most frequently asleep on the same minute? Again, return guard id multiplied by the minute number.
For full problem description, please see Advent of Code Day 4
Concerns
I'm a big fan of Java 8 Stream API and C# Linq, I kind of expected Python to be more like that. I'm not sure if the nested function calls like sorted(list(...))
or len(list(...))
are "Pythonic". Likewise, it feels like I should be able to use some reducer-like function calls instead of imperatively looping through stuff to find the most common sleeper of some kind. Or is the way I have written this code the Python way to do it?
Code
from dataclasses import dataclass
from datetime import datetime
from days import read_file
from enum import Enum
from collections import defaultdict, namedtuple
from statistics import mode
import statistics
import operator
import re
class EventType(Enum):
STARTS_SHIFT = 1
FALLS_ASLEEP = 2
WAKES_UP = 3
@dataclass
class Event:
time: datetime
guard: int
event: EventType
@dataclass
class GuardSleep:
sleep_total: int
last_sleep: int
sleeps: list
def add_sleeps(self, minute):
for i in range(self.last_sleep, minute):
self.sleeps.append(i)
def get_guard(line: str):
if "Guard" in line:
guard_id = re.search("Guard #(\d+)", line)
return int(guard_id.group(1))
return -1
def event_type(line):
if "begins shift" in line:
return EventType.STARTS_SHIFT
if "falls asleep" in line:
return EventType.FALLS_ASLEEP
if "wakes up" in line:
return EventType.WAKES_UP
raise Exception("Unknown line: " + line)
def day4() -> (int, int):
events = sorted(list(Event(datetime.strptime(line[1:17], "%Y-%m-%d %H:%M"), get_guard(line), event_type(line)) for line in read_file(4)), key=operator.attrgetter("time"))
guard = -1
guardsleep = defaultdict(lambda: GuardSleep(0, 0, ))
for event in events:
if event.guard >= 0:
guard = event.guard
if event.event == EventType.FALLS_ASLEEP:
guardsleep[guard].last_sleep = event.time.minute
if event.event == EventType.WAKES_UP:
guardsleep[guard].sleep_total += event.time.minute - guardsleep[guard].last_sleep
guardsleep[guard].add_sleeps(event.time.minute)
most_sleepy_guard_number = max(guardsleep, key=(lambda key: guardsleep[key].sleep_total))
most_sleepy_guard = guardsleep[most_sleepy_guard_number]
part1_result = most_sleepy_guard_number * mode(sorted(most_sleepy_guard.sleeps))
# Part 2
MostSleepy = namedtuple('MostCommon', ['id', 'minute', 'amount'])
most_sleepy = MostSleepy(0, 0, 0)
for k in guardsleep:
current_guard = guardsleep[k]
try:
most_common_minute = mode(sorted(current_guard.sleeps))
amount = len(list((m for m in current_guard.sleeps if m == most_common_minute)))
if amount > most_sleepy.amount:
most_sleepy = MostSleepy(k, most_common_minute, amount)
except statistics.StatisticsError:
print("No unique most common minute for " + str(k))
return part1_result, most_sleepy.id * most_sleepy.minute
if __name__ == '__main__':
print(day4())
python python-3.x programming-challenge
Introduction
I'm using Advent of Code 2018 to learn Python better, interested in the new type support for Python 3.7, I decided to go with that.
Here is my solution to Advent of Code Day 4, both part 1 and 2. I'm returning the answers for both part 1 and 2 as a tuple.
Problem Description
The problem essentially boils down to: Given a timestamped unsorted list of events of guards beginning their shift, waking up and falling asleep, determine the following:
Part 1: Which guard is asleep the most and on which minute is that guard mostly asleep? Return guard id multiplied by the minute number.
Part 2: Which guard is most frequently asleep on the same minute? Again, return guard id multiplied by the minute number.
For full problem description, please see Advent of Code Day 4
Concerns
I'm a big fan of Java 8 Stream API and C# Linq, I kind of expected Python to be more like that. I'm not sure if the nested function calls like sorted(list(...))
or len(list(...))
are "Pythonic". Likewise, it feels like I should be able to use some reducer-like function calls instead of imperatively looping through stuff to find the most common sleeper of some kind. Or is the way I have written this code the Python way to do it?
Code
from dataclasses import dataclass
from datetime import datetime
from days import read_file
from enum import Enum
from collections import defaultdict, namedtuple
from statistics import mode
import statistics
import operator
import re
class EventType(Enum):
STARTS_SHIFT = 1
FALLS_ASLEEP = 2
WAKES_UP = 3
@dataclass
class Event:
time: datetime
guard: int
event: EventType
@dataclass
class GuardSleep:
sleep_total: int
last_sleep: int
sleeps: list
def add_sleeps(self, minute):
for i in range(self.last_sleep, minute):
self.sleeps.append(i)
def get_guard(line: str):
if "Guard" in line:
guard_id = re.search("Guard #(\d+)", line)
return int(guard_id.group(1))
return -1
def event_type(line):
if "begins shift" in line:
return EventType.STARTS_SHIFT
if "falls asleep" in line:
return EventType.FALLS_ASLEEP
if "wakes up" in line:
return EventType.WAKES_UP
raise Exception("Unknown line: " + line)
def day4() -> (int, int):
events = sorted(list(Event(datetime.strptime(line[1:17], "%Y-%m-%d %H:%M"), get_guard(line), event_type(line)) for line in read_file(4)), key=operator.attrgetter("time"))
guard = -1
guardsleep = defaultdict(lambda: GuardSleep(0, 0, ))
for event in events:
if event.guard >= 0:
guard = event.guard
if event.event == EventType.FALLS_ASLEEP:
guardsleep[guard].last_sleep = event.time.minute
if event.event == EventType.WAKES_UP:
guardsleep[guard].sleep_total += event.time.minute - guardsleep[guard].last_sleep
guardsleep[guard].add_sleeps(event.time.minute)
most_sleepy_guard_number = max(guardsleep, key=(lambda key: guardsleep[key].sleep_total))
most_sleepy_guard = guardsleep[most_sleepy_guard_number]
part1_result = most_sleepy_guard_number * mode(sorted(most_sleepy_guard.sleeps))
# Part 2
MostSleepy = namedtuple('MostCommon', ['id', 'minute', 'amount'])
most_sleepy = MostSleepy(0, 0, 0)
for k in guardsleep:
current_guard = guardsleep[k]
try:
most_common_minute = mode(sorted(current_guard.sleeps))
amount = len(list((m for m in current_guard.sleeps if m == most_common_minute)))
if amount > most_sleepy.amount:
most_sleepy = MostSleepy(k, most_common_minute, amount)
except statistics.StatisticsError:
print("No unique most common minute for " + str(k))
return part1_result, most_sleepy.id * most_sleepy.minute
if __name__ == '__main__':
print(day4())
python python-3.x programming-challenge
python python-3.x programming-challenge
asked yesterday
Simon Forsberg♦
48.5k7129286
48.5k7129286
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Replacing chained if
with dictionary lookup
This function:
def event_type(line):
if "begins shift" in line:
return EventType.STARTS_SHIFT
if "falls asleep" in line:
return EventType.FALLS_ASLEEP
if "wakes up" in line:
return EventType.WAKES_UP
raise Exception("Unknown line: " + line)
isn't bad, but chained if
like this smell. It may be better represented as a dictionary, where the key is the string above, the value is the enum value, and you do a simple key lookup based on the last two words of every line. Whereas chained if
is worst-case O(n), dictionary lookup is O(1). Then - no if
s needed, and you get the exception for free if key lookup fails.
Use raw strings
re.search("Guard #(\d+)", line)
should be
re.search(r"Guard #(d+)", line)
Settle down with the one-liners
This:
events = sorted(list(Event(datetime.strptime(line[1:17], "%Y-%m-%d %H:%M"), get_guard(line), event_type(line)) for line in read_file(4)), key=operator.attrgetter("time"))
is effectively illegible. Break this up into multiple lines - including a temporary variable for the strptime
, as well as linebreaks in the list comprehension itself.
Don't use lists if you can use tuples
This:
MostSleepy = namedtuple('MostCommon', ['id', 'minute', 'amount'])
should be
MostSleepy = namedtuple('MostCommon', ('id', 'minute', 'amount'))
for various reasons - tuples are immutable, so use them for immutable data; and under certain narrow contexts (certainly not this one) they're faster.
Use a sum instead of a list constructor
This:
amount = len(list((m for m in current_guard.sleeps if m == most_common_minute)))
should be
amount = sum(1 for m in current_guard.sleeps if m == most_common_minute)
(Also, even if you kept using len
, you should use a tuple
constructor instead of a list
constructor.)
Another footnote - don't put inner parens in expressions like list((...generator...))
. Constructors can accept generator expressions directly.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210869%2fadvent-of-code-2018-day-4-pythonic-sleepy-guards%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Replacing chained if
with dictionary lookup
This function:
def event_type(line):
if "begins shift" in line:
return EventType.STARTS_SHIFT
if "falls asleep" in line:
return EventType.FALLS_ASLEEP
if "wakes up" in line:
return EventType.WAKES_UP
raise Exception("Unknown line: " + line)
isn't bad, but chained if
like this smell. It may be better represented as a dictionary, where the key is the string above, the value is the enum value, and you do a simple key lookup based on the last two words of every line. Whereas chained if
is worst-case O(n), dictionary lookup is O(1). Then - no if
s needed, and you get the exception for free if key lookup fails.
Use raw strings
re.search("Guard #(\d+)", line)
should be
re.search(r"Guard #(d+)", line)
Settle down with the one-liners
This:
events = sorted(list(Event(datetime.strptime(line[1:17], "%Y-%m-%d %H:%M"), get_guard(line), event_type(line)) for line in read_file(4)), key=operator.attrgetter("time"))
is effectively illegible. Break this up into multiple lines - including a temporary variable for the strptime
, as well as linebreaks in the list comprehension itself.
Don't use lists if you can use tuples
This:
MostSleepy = namedtuple('MostCommon', ['id', 'minute', 'amount'])
should be
MostSleepy = namedtuple('MostCommon', ('id', 'minute', 'amount'))
for various reasons - tuples are immutable, so use them for immutable data; and under certain narrow contexts (certainly not this one) they're faster.
Use a sum instead of a list constructor
This:
amount = len(list((m for m in current_guard.sleeps if m == most_common_minute)))
should be
amount = sum(1 for m in current_guard.sleeps if m == most_common_minute)
(Also, even if you kept using len
, you should use a tuple
constructor instead of a list
constructor.)
Another footnote - don't put inner parens in expressions like list((...generator...))
. Constructors can accept generator expressions directly.
add a comment |
Replacing chained if
with dictionary lookup
This function:
def event_type(line):
if "begins shift" in line:
return EventType.STARTS_SHIFT
if "falls asleep" in line:
return EventType.FALLS_ASLEEP
if "wakes up" in line:
return EventType.WAKES_UP
raise Exception("Unknown line: " + line)
isn't bad, but chained if
like this smell. It may be better represented as a dictionary, where the key is the string above, the value is the enum value, and you do a simple key lookup based on the last two words of every line. Whereas chained if
is worst-case O(n), dictionary lookup is O(1). Then - no if
s needed, and you get the exception for free if key lookup fails.
Use raw strings
re.search("Guard #(\d+)", line)
should be
re.search(r"Guard #(d+)", line)
Settle down with the one-liners
This:
events = sorted(list(Event(datetime.strptime(line[1:17], "%Y-%m-%d %H:%M"), get_guard(line), event_type(line)) for line in read_file(4)), key=operator.attrgetter("time"))
is effectively illegible. Break this up into multiple lines - including a temporary variable for the strptime
, as well as linebreaks in the list comprehension itself.
Don't use lists if you can use tuples
This:
MostSleepy = namedtuple('MostCommon', ['id', 'minute', 'amount'])
should be
MostSleepy = namedtuple('MostCommon', ('id', 'minute', 'amount'))
for various reasons - tuples are immutable, so use them for immutable data; and under certain narrow contexts (certainly not this one) they're faster.
Use a sum instead of a list constructor
This:
amount = len(list((m for m in current_guard.sleeps if m == most_common_minute)))
should be
amount = sum(1 for m in current_guard.sleeps if m == most_common_minute)
(Also, even if you kept using len
, you should use a tuple
constructor instead of a list
constructor.)
Another footnote - don't put inner parens in expressions like list((...generator...))
. Constructors can accept generator expressions directly.
add a comment |
Replacing chained if
with dictionary lookup
This function:
def event_type(line):
if "begins shift" in line:
return EventType.STARTS_SHIFT
if "falls asleep" in line:
return EventType.FALLS_ASLEEP
if "wakes up" in line:
return EventType.WAKES_UP
raise Exception("Unknown line: " + line)
isn't bad, but chained if
like this smell. It may be better represented as a dictionary, where the key is the string above, the value is the enum value, and you do a simple key lookup based on the last two words of every line. Whereas chained if
is worst-case O(n), dictionary lookup is O(1). Then - no if
s needed, and you get the exception for free if key lookup fails.
Use raw strings
re.search("Guard #(\d+)", line)
should be
re.search(r"Guard #(d+)", line)
Settle down with the one-liners
This:
events = sorted(list(Event(datetime.strptime(line[1:17], "%Y-%m-%d %H:%M"), get_guard(line), event_type(line)) for line in read_file(4)), key=operator.attrgetter("time"))
is effectively illegible. Break this up into multiple lines - including a temporary variable for the strptime
, as well as linebreaks in the list comprehension itself.
Don't use lists if you can use tuples
This:
MostSleepy = namedtuple('MostCommon', ['id', 'minute', 'amount'])
should be
MostSleepy = namedtuple('MostCommon', ('id', 'minute', 'amount'))
for various reasons - tuples are immutable, so use them for immutable data; and under certain narrow contexts (certainly not this one) they're faster.
Use a sum instead of a list constructor
This:
amount = len(list((m for m in current_guard.sleeps if m == most_common_minute)))
should be
amount = sum(1 for m in current_guard.sleeps if m == most_common_minute)
(Also, even if you kept using len
, you should use a tuple
constructor instead of a list
constructor.)
Another footnote - don't put inner parens in expressions like list((...generator...))
. Constructors can accept generator expressions directly.
Replacing chained if
with dictionary lookup
This function:
def event_type(line):
if "begins shift" in line:
return EventType.STARTS_SHIFT
if "falls asleep" in line:
return EventType.FALLS_ASLEEP
if "wakes up" in line:
return EventType.WAKES_UP
raise Exception("Unknown line: " + line)
isn't bad, but chained if
like this smell. It may be better represented as a dictionary, where the key is the string above, the value is the enum value, and you do a simple key lookup based on the last two words of every line. Whereas chained if
is worst-case O(n), dictionary lookup is O(1). Then - no if
s needed, and you get the exception for free if key lookup fails.
Use raw strings
re.search("Guard #(\d+)", line)
should be
re.search(r"Guard #(d+)", line)
Settle down with the one-liners
This:
events = sorted(list(Event(datetime.strptime(line[1:17], "%Y-%m-%d %H:%M"), get_guard(line), event_type(line)) for line in read_file(4)), key=operator.attrgetter("time"))
is effectively illegible. Break this up into multiple lines - including a temporary variable for the strptime
, as well as linebreaks in the list comprehension itself.
Don't use lists if you can use tuples
This:
MostSleepy = namedtuple('MostCommon', ['id', 'minute', 'amount'])
should be
MostSleepy = namedtuple('MostCommon', ('id', 'minute', 'amount'))
for various reasons - tuples are immutable, so use them for immutable data; and under certain narrow contexts (certainly not this one) they're faster.
Use a sum instead of a list constructor
This:
amount = len(list((m for m in current_guard.sleeps if m == most_common_minute)))
should be
amount = sum(1 for m in current_guard.sleeps if m == most_common_minute)
(Also, even if you kept using len
, you should use a tuple
constructor instead of a list
constructor.)
Another footnote - don't put inner parens in expressions like list((...generator...))
. Constructors can accept generator expressions directly.
edited yesterday
answered yesterday
Reinderien
3,832821
3,832821
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210869%2fadvent-of-code-2018-day-4-pythonic-sleepy-guards%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown