Summing numbers with Iterators in Rust | Advent of Code 2022 Day 1

  Рет қаралды 22,849

chris biscardi

chris biscardi

Күн бұрын

Пікірлер
@aranasaurus
@aranasaurus 2 жыл бұрын
I loved this! I’m doing AoC in rust this year to learn/get better with rust. So being able to watch your process for solving a problem I just solved myself, in detail like this is a huge help! I was able to pick up on a bunch of rust idioms just by you talking through your approach to the problem and considering your options, so I really hope you keep doing these, and keep the detailed talking through the problem in!
@markday3145
@markday3145 2 жыл бұрын
I, too, really like seeing how other people approach a problem. I almost always learn something new. And I really appreciate Chris talking through the problem and the solution rather than just presenting a solution (it's often that talking through it part where I learn something).
@Zzznmop
@Zzznmop 2 жыл бұрын
Plus one to this! as a noob to rust, I can get a basic program written jogging my C++ memories, but it is hard to know how “good” that solution is without exploring all the tools available in rust :)
@dmhowcroft
@dmhowcroft 2 жыл бұрын
Yeah, same--I'm coming from Python and don't often use map-apply programming patterns, so seeing how a Rust programmer solves these problems after I've done it in my hacky way is great for learning the style differences between the languages :)
@squelchedotter
@squelchedotter 2 жыл бұрын
The reason you can't sort an iterator is because it wouldn't have anywhere to store it. An iterator only has access to the current value, not past or future ones. Thus sorting requires collecting all of the elements into some sort of new container, which can then be sorted in place. This is what itertools does.
@chrisbiscardi
@chrisbiscardi 2 жыл бұрын
If that's what itertools does then there's no technical restriction to it being implemented. Yes, you can't sort an Iterator in-place because it requires all of the values, but terminating functions like collect have to create a new Vec anyway. The Iterator trait itself doesn't preclude this behavior from existing in the stdlib. Also, I was able to find the reason after the recording! Basically nobody seems to have RFC'd the functionality into the stdlib: github.com/rust-lang/rust/issues/38882
@icelk
@icelk 2 жыл бұрын
@@chrisbiscardi I think the reason for a sort method on iterators not being implemented is to avoid confusion about allocation. Iterators are also lazy, and sorting them completely defeats that. The trait is also defined in `core::iter::Iterator`, where an allocator isn't available.
@rutabega306
@rutabega306 2 жыл бұрын
Doesn't seem so hard to collect into a Vec first then sort. And that makes it clear what the memory implications are!
@mzg147
@mzg147 Жыл бұрын
But what about making an index array? The Sort iterator would have a [u32] array that specifies the sorted order, e.g. for vec![2,3,1] it would be [2,0,1] Or with another approach, each next invocation for the iterator would find the n-th lowest element. That would be less optimal though, but didn't require memory
@yaksher
@yaksher Жыл бұрын
@@mzg147 A generic iterator can't be traversed multiple times; it might mutate or consume state, for example.
@markday3145
@markday3145 2 жыл бұрын
I ended up solving this one almost the same way you did, and then experimented with other ideas just for the sake of learning. A few observations: There are also sort_unstable, sort_unstable_by, etc. They can be more efficient if it is OK to rearrange values that compare equal. On a problem of this size, the performance difference would be tiny; but it's good to know about for those cases when you have much larger inputs. For parsing the numbers, you can do: .map(str::parse::) (with no closure). I find that just a little easier to read. To sort in reverse, you can do: .sort_by(|a, b| a.cmp(b).reverse()) I think that more obviously conveys that you want it sorted in reverse. It's easy to overlook that `a` and `b` were swapped in the closure. There is also sort_by_key() combined with std::cmp::Reverse, which I find a little harder to read (and remember). I really hope you will post more Advent of Code videos. I enjoy seeing how other people approach problems, including going back and refining a solution.
@michaelalls8230
@michaelalls8230 2 жыл бұрын
As someone trying to use AOC to learn Rust this is great! Learning so much! Thank You!
@devbites77
@devbites77 Жыл бұрын
Thoroughly explained, and thoroughly enjoying learning rust.
@drewmiddleton9715
@drewmiddleton9715 2 жыл бұрын
this is awesome thank you. I just tackled problem 1 in Python and am starting to learn Rust, so will be following along with this series to try and learn :)
@ballingt
@ballingt 2 жыл бұрын
Everything here is helpful, but gosh thanks for the project setup notes! Exactly what will be helpful when I get around to day 3 tonight.
@tobiasgraf5246
@tobiasgraf5246 2 жыл бұрын
Thx for sharing your solution. I'm currently learning rust and use advent of code to play around with the language, and it's very helpful to have you explain certain aspects. Tomorrow, I will have to change my repository to your setup. That looks way more reasonable than mine 😅
@gergelypaless5042
@gergelypaless5042 2 жыл бұрын
Looking forward to this! I am also planning to do this myself. Interested in your solutions😁 Keep it up!
@laupetre
@laupetre 2 жыл бұрын
Great video! Looking forward to learning rust with this version of AoC
@conoroneill8067
@conoroneill8067 2 жыл бұрын
Same here. Good luck!
@inzyster
@inzyster 2 жыл бұрын
I've been meaning to start learning Rust. I mainly work with C#, so this will be very useful!
@opposite342
@opposite342 2 жыл бұрын
I'm mindblown by the FP usage here
@adityasanthosh702
@adityasanthosh702 Жыл бұрын
If anyone is doing this on windows, you will encounter an error while you are splitting because in Windows, the line seperators are instead of
@phenanrithe
@phenanrithe 2 жыл бұрын
Funny challenge, though the questions are released in the middle of the night so I'm not even paying attention to the indicated delay to solve them. The delay should count from the instant the question is shown. +1 point for the TDD approach! I used itertools and coalesce so that I don't have to load the whole file in memory. I know it's not that big, it's just for the sake of trying.
@erifetim
@erifetim 2 жыл бұрын
Probably wouldn't work for global ranking, but for personal scores I'd absolutely love to have a "time since opening the challenge".
@phenanrithe
@phenanrithe 2 жыл бұрын
@@erifetim True, that wouldn't work for global ranking.
@vladimirbauer6604
@vladimirbauer6604 2 жыл бұрын
If you don't want to panic on bad input value, you can do '.filter_map(|item| item.parse::().ok())' instead which will just skip bad value.
@Andrew-jh2bn
@Andrew-jh2bn 2 жыл бұрын
In this case I think it would be better to panic or return an error than just silently ignore parsing issues.
@BlackSharkfr
@BlackSharkfr 2 жыл бұрын
Since the sums are stored in a Vector, I would have sorted normally and then used iter().rev().take(3)
@markday3145
@markday3145 2 жыл бұрын
Good suggestion. I ended up sorting, then calling .reverse(), then .iter().take(3).sum(). I forgot about reverse iterators. The .rev() method to turn a forward iterator into a reverse iterator just feels weird to me, an so I tend to forget about it. I would expect something like .iter_rev() or similar to directly construct a reverse iterator. (I get why they did it that way. That one method can be applied to iterators producing owned values, shared references, or exclusive references.)
@jasperdevries1726
@jasperdevries1726 2 жыл бұрын
Like you said, parse returns a result but max returns an Option. While you want to unwrap them both in this case, they are quite different.
@benibachmann9274
@benibachmann9274 2 жыл бұрын
Also trying to do this year‘s AoC with Rust again! My goal is to reach the top 100 once. But it’s not looking very realistic after day 1. 😂
@krige
@krige 2 жыл бұрын
1:45 Why did choose to use --lib?
@chrisbiscardi
@chrisbiscardi 2 жыл бұрын
I chose --lib because I knew I was going to set up my binaries in the bin folder, so instead of generating a main.rs, --lib generates a lib.rs with a test that my bin folder can use
@mustafazakiassagaf1757
@mustafazakiassagaf1757 2 жыл бұрын
hey i don't get why sum need a type, won't rust know the type from parse?
@jomy10-games
@jomy10-games 2 жыл бұрын
I’m writing every puzzle in a different language this year. I did the first day in shell script
@krige
@krige 2 жыл бұрын
1:38 ... you don't need because you are using what?
@chrisbiscardi
@chrisbiscardi 2 жыл бұрын
www.nushell.sh/
@iuiz
@iuiz 2 жыл бұрын
This video is missing how you developed the code step by step :(. The whole using closures part is elegant, when it is ready, but when I want to add a simple println in the closure without the rest of them, I get errors, because I need to assign the typed correctly. This feels like a "write everything at once" solution and not something you can develop organically. I went for two for loops instead, which looks awful, but as I am new to Rust i could develop it step by step. However thank you for your video and the provided insights.
@chrisbiscardi
@chrisbiscardi 2 жыл бұрын
How are you adding the println? and what do you mean by "without the rest of them"? Do you mean that you want to have a println at an arbitrary location in the chain? If so there's a function for that: inspect. Here's a link to the documentation for it: doc.rust-lang.org/std/iter/trait.Iterator.html#method.inspect and I would also suggest using the dbg! macro instead of println! for debugging purposes. Personally, my step-by-step *was* write the code from top to bottom so I edited out the typing and covered the result. I wasn't doing any sort of debugging or whatnot. What sort of additional explanation are you looking for? Is it the existence of the iterator functions and where to find them?
@iuiz
@iuiz 2 жыл бұрын
@@chrisbiscardi Thank you very much for your time to answer. I dive deeper into Rust every day and it gets a bit clearer. I cannot answer anymore, what exactly I did wrong, but ownership issues after the collect is something I keep running into. I could do the day 3 solution kinda slow but it worked out thanks to your tutorials :). dbg! seems to have some problems with claiming ownership and destroys code I had after it, so I switched back to println and the real debugger. I might skip a day to do some more basic Rust tutorials. Thanks again for all your videos.
@kewang7473
@kewang7473 Жыл бұрын
Why not binaryheap
@magnusmarkling
@magnusmarkling 2 жыл бұрын
How would you "group the values using itertools"? Would love to see that!
@chrisbiscardi
@chrisbiscardi 2 жыл бұрын
I probably would've ended up using coalesce like this: play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a8f94ea0b82ce025dfe198aab4ee4784 The coalesce uses the outer Result to do the iteration, while the inner Result is the result from our parse. Otherwise the answer is mostly the same docs.rs/itertools/latest/itertools/trait.Itertools.html#method.coalesce
@erifetim
@erifetim 2 жыл бұрын
Nice, love comparing solutions and not just blatantly copying yours because I'm stuck! I was thinking if it was possible to extend the Iterator trait such that you could pick the "top_3()" items or something. Digging through the Iterator file, it was a little too intimidating to start anything
@chrisbiscardi
@chrisbiscardi 2 жыл бұрын
you could start with using scan, using a 3 element sorted array as the state and then write an extension trait that uses scan behind the scenes doc.rust-lang.org/std/iter/trait.Iterator.html#method.scan
@gnu-linux2728
@gnu-linux2728 2 жыл бұрын
Dude I tray to get the code with git clone ........ but maybe something ist wrong with your repo
@petarvujovic
@petarvujovic 2 жыл бұрын
I solved this challenge in almost the exact same way about an hour ago. Love to see people thinking in a similar way to myself
@CuriousSpy
@CuriousSpy 2 жыл бұрын
You cannot use sort to iter because iter have access to next element like linkedlist, but when you sorting array you need access to an entire array
@chair547
@chair547 2 жыл бұрын
Collecting and sorting is nlogn and memory inefficient. It should be possible to get the top 3 without collecting or sorting and also being o(n)
@echobucket
@echobucket 2 жыл бұрын
Wow people actually use nushell. I mean I think it's cool, but I've been using bash/zsh too long.
@chrisbiscardi
@chrisbiscardi 2 жыл бұрын
Nushell has been my primary shell for over a year now. I still have some bash/zsh isms in my fingers but it's been really solid for me and I really enjoy the data features
@jawad9757
@jawad9757 2 жыл бұрын
kinda spoiling it by putting the code for the solution in the thumbnail, esp for people who haven't had the chance to do it yet
@burnere633
@burnere633 2 жыл бұрын
Hi. Request: could you not provide hints in the title of AoC videos? :)
@chrisbiscardi
@chrisbiscardi 2 жыл бұрын
hey! I'm happy to try. Did you feel like today's title was too much of a hint? I felt like the question asked us to sum numbers pretty directly.
@burnere633
@burnere633 2 жыл бұрын
@@chrisbiscardi I don't know, I haven't yet looked at today's problem; so now you've already biased me in some way. :D
@carterplasek498
@carterplasek498 2 жыл бұрын
@@chrisbiscardi I was reminded to participate today by your video, and just seeing the parse function in the glance at the thumbnail felt like too much of a hint, especially since all of the code is in the thumbnail, I think the title was subtle enough though
@echoptic775
@echoptic775 2 жыл бұрын
Im impressed how can you talk so much without saying anything and do so much without doing anything
@magnusmarkling
@magnusmarkling 2 жыл бұрын
And still be a pleasure to listen to!
@verified_tinker1818
@verified_tinker1818 2 жыл бұрын
You can do Part 2 in one pass and without a heap allocation by using `fold()`: ``` pub fn sum_top_3(input: &str) -> u32 { input .split(" ") .map(|food_items_per_elf| { food_items_per_elf .lines() .map(|calories_per_item| calories_per_item.parse::().unwrap()) .sum::() }) .fold([0, 0, 0], |mut top_3, calories_per_elf| { // The `unwrap()` could be avoided by writing `if let Some(min)`, // but I believe it's better to be explicit. `if let` would fail silently. let min = top_3.iter_mut().min().unwrap(); *min = u32::max(calories_per_elf, *min); top_3 }) .into_iter() .sum() } ``` This gives you a time complexity of O(n) and a space complexity of O(1).
@QmVuamFtaW4
@QmVuamFtaW4 Жыл бұрын
i came up with something like this 💀 let file = fs::read_to_string("input.txt").expect("Error reading input file"); let mut vec: Vec = Vec::new(); let mut sum = 0; let mut largest = 0; for i in file.split(" ") { for j in i.split(" ") { sum += match j.parse::() { Ok(val) => val, Err(..) => 0, }; } vec.push(sum); if sum > largest { largest = sum; } sum = 0; } vec.sort_by(|a, b| b.cmp(a)); for i in 0..=2 { sum += vec[i]; }
Rock, Paper, Scissors... and Traits | Advent of Code 2022 Day 2
21:20
chris biscardi
Рет қаралды 10 М.
Rust's Most Important Containers 📦 10 Useful Patterns
17:11
Code to the Moon
Рет қаралды 131 М.
Tuna 🍣 ​⁠@patrickzeinali ​⁠@ChefRush
00:48
albert_cancook
Рет қаралды 148 МЛН
黑天使只对C罗有感觉#short #angel #clown
00:39
Super Beauty team
Рет қаралды 36 МЛН
How to treat Acne💉
00:31
ISSEI / いっせい
Рет қаралды 108 МЛН
Rust Tests Itself (kind of!)
11:41
No Boilerplate
Рет қаралды 78 М.
Rust Before Main - Ryan Levick - Rust Linz, July 2022
31:34
I built a real HTTP sever in ARM assembly in under 200 lines
22:34
How to read complicated Rust types
20:17
chris biscardi
Рет қаралды 55 М.
The Dome Paradox: A Loophole in Newton's Laws
22:59
Up and Atom
Рет қаралды 701 М.
Rust Functions Are Weird (But Be Glad)
19:52
Logan Smith
Рет қаралды 143 М.
Ace Rust Macros ♠️ the declarative kind
14:06
Code to the Moon
Рет қаралды 41 М.
Rust Powered Database SurrealDB (It's Pretty Ambitious)
11:28
Code to the Moon
Рет қаралды 111 М.
5 traits your Rust types must implement
10:39
Let's Get Rusty
Рет қаралды 63 М.
Tuna 🍣 ​⁠@patrickzeinali ​⁠@ChefRush
00:48
albert_cancook
Рет қаралды 148 МЛН