10 votes

Day 6: Custom Customs

Today's problem description: https://adventofcode.com/2020/day/6


Join the Tildes private leaderboard! You can do that on this page, by entering join code 730956-de85ce0c.

Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace python with any of the "short names" listed in this page of supported languages):

<details>
<summary>Part 1</summary>

```python
Your code here.
```

</details>

22 comments

  1. [2]
    clone1
    Link
    Posting python today because I like how it turned out. Part 1 & 2 def parse(x): return x.rstrip() def split(lines): res = [] lin = [] for line in lines: if line == "": res.append(lin) lin = []...

    Posting python today because I like how it turned out.

    Part 1 & 2
    def parse(x):
        return x.rstrip()
    
    def split(lines):
        res = []
        lin = []
        for line in lines:
            if line == "":
                res.append(lin)
                lin = []
            else:
                lin.append(set([x for x in line]))
        res.append(lin)
        return res
    
    def one(lines):
        return sum(map(lambda g: len(set.union(*g)), lines))
    
    def two(lines):
        return sum(map(lambda g: len(set.intersection(*g)), lines))
    
    
    f = open("input", "r")
    
    lines = [parse(x) for x in f]
    lines = split(lines)
    
    print("One: " + str(one(lines)))
    print("Two: " + str(two(lines)))
    
    6 votes
    1. thorondir
      Link Parent
      That is... Very elegant. :D I hand crafted the sets using dictionaries, and then compared the count of items with the count of members in the group.

      That is...
      Very elegant. :D

      I hand crafted the sets using dictionaries, and then compared the count of items with the count of members in the group.

      2 votes
  2. Crespyl
    Link
    Quick and dirty: Ruby Part 1 #!/usr/bin/env ruby require "set" input = File.read(ARGV[0] || "test.txt") groups = input.split("\n\n") yes_answers = groups.map { |g| g.lines.reduce(Set.new) { |set,...

    Quick and dirty:

    Ruby

    Part 1
    #!/usr/bin/env ruby
    
    require "set"
    
    input = File.read(ARGV[0] || "test.txt")
    
    groups = input.split("\n\n")
    
    yes_answers = groups.map { |g| g.lines.reduce(Set.new) { |set, line| set | line.strip.chars } }
    
    sum = yes_answers.reduce(0) { |sum, group| sum + group.size }
    
    puts "Part 1"
    puts sum
    
    Part 2
    puts "Part 2"
    yes_answers = groups.map { |g| g.lines.reduce(Set.new(g.lines.first.strip.chars)) { |set, line| set & line.strip.chars } }
    sum = yes_answers.reduce(0) { |sum, group| sum + group.size }
    puts sum
    

    Having a built in set class makes this one pretty easy. The set union/intersection operator overloads are handy too.

    4 votes
  3. archevel
    (edited )
    Link
    Went with Python yet again. Got inspired by the ruby solution by @Crespyl so rewrote the python code to part two to make it a bit cleaner! Part 1 from functools import reduce groups = [set()] for...

    Went with Python yet again. Not too happy with solution to part two... Got inspired by the ruby solution by @Crespyl so rewrote the python code to part two to make it a bit cleaner!

    Part 1
    from functools import reduce
    
    groups = [set()]
    for line in sys.stdin.readlines():
        line = line[:-1]
        if line == '':
            groups.append(set())
        else:
            groups[-1] = groups[-1].union(set(list(line)))
    
    
    print(reduce(lambda acc, s: len(s) + acc, groups, 0))
    
    Part 2 What is the cleaner way of handling the new groups? Feels a bit hacky to do the boolean global variable... (edit: see cleaner version below)
    import sys
    from functools import reduce
    
    groups = []
    newgroup = True
    for line in sys.stdin.readlines():
        line = line[:-1]
        if line == '':
            newgroup = True
        elif newgroup:
            newgroup = False
            groups.append(set(list(line)))
        else:
            groups[-1] = groups[-1].intersection(set(list(line)))
    
    
    print(reduce(lambda acc, s: len(s) + acc, groups, 0))
    
    Part 2 (cleaner version)
    import sys
    from functools import reduce
    
    def parseGroup(g):
        answers = [set(list(a)) for a in g.split("\n") if a != '']
        return set.intersection(*answers)
    
    groups = [parseGroup(g) for g in sys.stdin.read().split("\n\n")]
    print(reduce(lambda acc, s: len(s) + acc, groups, 0))
    
    4 votes
  4. [2]
    markh
    Link
    Elixir! Took me a while to realize what part two was asking for. Parts One and Two defmodule Day6 do def one do File.read!("inputs/six.txt") |> String.split("\n\n") |> Enum.map(&String.replace(&1,...

    Elixir! Took me a while to realize what part two was asking for.

    Parts One and Two
    defmodule Day6 do
      def one do
        File.read!("inputs/six.txt")
        |> String.split("\n\n")
        |> Enum.map(&String.replace(&1, "\n", "", global: true))
        |> Enum.map(&String.split(&1, "", trim: true))
        |> Enum.map(&MapSet.new(&1))
        |> Enum.map(&MapSet.size(&1))
        |> Enum.reduce(&(&1 + &2))
      end
    
      def two do
        File.read!("inputs/six.txt")
        |> String.split("\n\n")
        |> Enum.map(&String.split(&1, "\n", trim: true))
        |> Enum.map(&parse/1)
        |> Enum.map(&MapSet.size/1)
        |> Enum.reduce(&(&1 + &2))
      end
    
      def parse(input) do
        input
        |> Enum.map(&String.graphemes(&1))
        |> Enum.map(&MapSet.new(&1))
        |> Enum.reduce(&MapSet.intersection/2)
      end
    end
    
    4 votes
    1. jzimbel
      Link Parent
      FYI, you can use Enum.sum/1 instead of Enum.reduce(&(&1 + &2))!

      FYI, you can use Enum.sum/1 instead of Enum.reduce(&(&1 + &2))!

      1 vote
  5. [2]
    PapaNachos
    (edited )
    Link
    This one wasn't too difficult. It helps if you know some different ways you can store data. Day 6 Part A – Python For this I just made a group as I parsed through the entry, then I cast each group...

    This one wasn't too difficult. It helps if you know some different ways you can store data.

    Day 6 Part A – Python

    For this I just made a group as I parsed through the entry, then I cast each group over to a set (which doesn't allow duplicates) and back to a list (which does). I typically use that method when I'm looking to find the unique entries within a list.

    After that it was just a matter of adding everything together

    database = input_data.split('\n')
    
    group_list = []
    
    current_group = []
    
    def split(word): 
        return [char for char in word]  
    
    for line in database:
        if line == '':
            group_list.append(list(set(current_group)))
            current_group = []
        else:
            for entry in split(line):
                current_group.append(entry)
    group_list.append(list(set(current_group)))
    
    count_sum = 0
    for group in group_list:
        count_sum = count_sum + len(group)
    print(count_sum)
    
    Day 6 Part B – Python

    Part B was a little bit more tricky, I had to rework my data structure a bit to track what each person individually said. Then I iterated through each letter and found ones that every person said yes to. It would probably be easier if I knew how to do an 'intersection' between the different lists.

    import string
    
    database = input_data.split('\n')
    
    group_list = []
    
    current_group = []
    
    def split(word): 
        return [char for char in word]
    
    def analyse_group(group):
        #print(group)
        all_contain = []
        for letter in list(string.ascii_lowercase):
            in_all = True
            for person in group:
                if letter in person:
                    pass
                else:
                    in_all = False
            if in_all == True:
                all_contain.append(letter)
        return all_contain
    
    for line in database:
        if line == '':
            group_list.append(analyse_group(current_group))
            current_group = []
        else:
            person = []
            for entry in split(line):
                person.append(entry)
            current_group.append(person)
    group_list.append(analyse_group(current_group))
    
    count_sum = 0
    for group in group_list:
        count_sum = count_sum + len(group)
    print(count_sum)
    
    Tips for Beginners
    • There are some similarities between this and day 4, at least in terms of how you read in the data. It can be helpful to reuse old code, or improve upon it if you've learned more since then

    • Your groups will have duplicate entries. You'll need to deal with them in some way. There are multiple options. Some of them mathematical, some of them using programming tricks, and others may take a brute force approach of checking every letter

    • For part A you only need to look at the group as a whole, but for part B it's necessary to look at each person individually and see how they compare to the rest of the group

    • Reading up on the difference between data structures can be useful. I use python and so I was able to use the difference between a set and a list to do some of the heavy lifting for part A. They language you're using may let you do something similar

    • If you want to do things more 'purely mathematically' you'll want to look up the term 'set theory' for the mathematical explanation or 'set operations [YOUR LANGUAGE]' for practical application

    3 votes
    1. Crestwave
      Link Parent
      Spoiler (do we need to hide these here?) Not necessarily. It may not be the cleanest, but in my solution I simply check if the occurrences of the letter is equal to the number of people, since one...
      Spoiler (do we need to hide these here?)

      For part A you only need to look at the group as a whole, but for part B it's necessary to look at each person individually and see how they compare to the rest of the group

      Not necessarily. It may not be the cleanest, but in my solution I simply check if the occurrences of the letter is equal to the number of people, since one person cannot answer the same question multiple times.

      4 votes
  6. Crestwave
    Link
    Well, this was nice and easy! Simple and hacky AWK solutions: Part 1 I just slap the characters to an (associative) array then add its length to the sum. #!/usr/bin/awk -f BEGIN { RS = "" } {...

    Well, this was nice and easy! Simple and hacky AWK solutions:

    Part 1

    I just slap the characters to an (associative) array then add its length to the sum.

    #!/usr/bin/awk -f
    BEGIN { RS = "" }
    
    {
    	gsub(/[^a-z]/, "")
    	split("", ans)
    
    	split($0, c, "")
    	for (i in c)
    		ans[c[i]] = 1
    	for (i in ans)
    		sum += 1
    }
    
    END { print sum }
    
    Part 2

    The same, but I add to the array's value and check if it's equal to the number of lines in the group.

    #!/usr/bin/awk -f
    BEGIN { RS = "" }
    
    {
    	num = gsub("\n", "") + 1
    	split("", ans)
    
    	split($0, c, "")
    	for (i in c)
    		ans[c[i]] += 1
    	for (i in ans)
    		if (ans[i] == num)
    			sum += 1
    }
    
    END { print sum }
    
    3 votes
  7. Lynx
    Link
    haskell again today, nice and concise. day6.hs Knowing about some data structures really pays off here - these are just set operations (union and intersection), so converting all the lines to sets...

    haskell again today, nice and concise.

    day6.hs Knowing about some data structures really pays off here - these are just set operations (union and intersection), so converting all the lines to sets and then folding them (in blank-line-separated groups) is really all it needs.
    import Data.Function (on)
    import Data.List (groupBy)
    import qualified Data.Set as S
    import           Data.Set (Set)
    
    splitOnEmptyLines :: String -> [[String]]
    splitOnEmptyLines = filter (not . any null) . groupBy ((==) `on` null) . lines
    
    main = do
        answerSets <- ((fmap . fmap) S.fromList . splitOnEmptyLines) <$> getContents
        let countSetsFolded f = sum $ map (S.size . foldr1 f) answerSets
        print $ countSetsFolded S.union
        print $ countSetsFolded S.intersection
    
    3 votes
  8. tomf
    (edited )
    Link
    Sheets again! While everybody else is all, 'oh! that was a breeze!' -- well, I'm writing some gnarly formulas here. Part 1 =ARRAYFORMULA( QUERY( UNIQUE( IFERROR( SPLIT( FLATTEN( IF(ISBLANK(A1:A),,...

    Sheets again! While everybody else is all, 'oh! that was a breeze!' -- well, I'm writing some gnarly formulas here.

    Part 1
    =ARRAYFORMULA(
      QUERY(
       UNIQUE(
        IFERROR(
         SPLIT(
          FLATTEN(
           IF(ISBLANK(A1:A),,
            VLOOKUP(
             ROW(A1:A),
             FILTER(
              ROW(INDIRECT("A1:A"&MAX(FILTER(ROW(A1:A),A1:A<>"")))),
              INDIRECT("A1:A"&MAX(FILTER(ROW(A1:A),A1:A<>"")))=""),
             1,TRUE)&
            "|"&
            SPLIT(
             IFERROR(
              REGEXREPLACE(
               ""&A1:A,
               "(.)",
               "$1,")),
             ","))),
          "|"))),
       "select Count(Col1) 
        where Col2 is not null 
        label Count(Col1) 'Part 1'",0))
    
    

    I have Part 2 in my sheet but it's 79 lines long with formatting... so I won't paste it here.

    I'm going to keep cracking away at this. There's gotta be a way to cut these formulas down without giving up my arrogant, 'I can do these with one formula' game.

    3 votes
  9. 3d12
    Link
    I'm 100% certain there's a more efficient way to do this, but mine works fine apparently. I was surprised at how similar this was to Day 4, at least in the "parse blocked input, and validate"...

    I'm 100% certain there's a more efficient way to do this, but mine works fine apparently. I was surprised at how similar this was to Day 4, at least in the "parse blocked input, and validate" aspect.

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let formArray = []
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		formArray.push(line);
    	}
    }
    
    function parseInput(input) {
    	let groupArray = [];
    	let currentGroup = "";
    	for (const line of input) {
    		if (line.trim().length == 0) {
    			groupArray.push(parseGroup(currentGroup.trim()));
    			currentGroup = "";
    		} else {
    			currentGroup += " " + line;
    		}
    	}
    	// flush the buffer, in case the file isn't newline-terminated
    	if (currentGroup != "") {
    		groupArray.push(parseGroup(currentGroup.trim()));
    	}
    	return groupArray;
    }
    
    function parseGroup(group) {
    	let distinctAnswers = [];
    	let answerBlocks = group.split(' ');
    	for (const answers of answerBlocks) {
    		for (const answer of answers) {
    			if (distinctAnswers.indexOf(answer) == -1) {
    				distinctAnswers.push(answer);
    			}
    		}
    	}
    	return distinctAnswers;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	console.log(parseInput(formArray).map(form => { return form.length }).reduce((a,b) => { return a + b }));
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let formArray = []
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		formArray.push(line);
    	}
    }
    
    function parseInput(input) {
    	let groupArray = [];
    	let currentGroup = "";
    	for (const line of input) {
    		if (line.trim().length == 0) {
    			groupArray.push(parseGroup(currentGroup.trim()));
    			currentGroup = "";
    		} else {
    			currentGroup += " " + line;
    		}
    	}
    	// flush the buffer, in case the file isn't newline-terminated
    	if (currentGroup != "") {
    		groupArray.push(parseGroup(currentGroup.trim()));
    	}
    	return groupArray;
    }
    
    function parseGroup(group) {
    	let everyoneAnswers = [];
    	let firstBlock = true;
    	let answerBlocks = group.split(' ');
    	for (const answers of answerBlocks) {
    		if (firstBlock) {
    			for (const answer of answers) {
    				everyoneAnswers.push(answer);
    			}
    			firstBlock = false;
    		} else {
    			for (const sharedAnswer of everyoneAnswers) {
    				if (everyoneAnswers.length == 0) {
    					break;
    				}
    				if (answers.indexOf(sharedAnswer) == -1) {
    					let popIndex = everyoneAnswers.indexOf(sharedAnswer);
    					everyoneAnswers = everyoneAnswers.slice(0, popIndex).concat(everyoneAnswers.slice(popIndex+1));
    				}
    			}
    		}
    	}
    	return everyoneAnswers;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	console.log(parseInput(formArray).map(form => { return form.length }).reduce((a,b) => { return a + b }));
    })();
    
    3 votes
  10. raevnos
    Link
    This year I'm using (chicken) scheme. Today's problems lended themselves to a short, elegant solution using sets. Both parts #!/usr/local/bin/csi -s (import (chicken format) (chicken io) (srfi 1)...

    This year I'm using (chicken) scheme. Today's problems lended themselves to a short, elegant solution using sets.

    Both parts
    #!/usr/local/bin/csi -s
    (import
     (chicken format)
     (chicken io)
     (srfi 1)
     (srfi 14))
    
    (define (read-group #!optional (port (current-input-port)))
      (let loop ((answers '())
                 (line (read-line port)))
        (if (or (eof-object? line) (string=? line ""))
            answers
            (loop (cons (string->char-set line) answers) (read-line port)))))
    
    (define (read-groups #!optional (port (current-input-port)))
      (let loop ((groups '()))
        (let ((new-group (read-group port)))
          (if (null? new-group)
              groups
              (loop (cons new-group groups))))))
    
    (define (solve reduce-op groups)
      (fold (lambda (group total)
              (+ total (char-set-size (reduce reduce-op (char-set) group))))
            0 groups))
    
    (define (solve1 groups) (solve char-set-union groups))
    (define (solve2 groups) (solve char-set-intersection groups))
    
    (define input (read-groups))
    (printf "Part 1: ~A~%" (solve1 input))
    (printf "Part 2: ~A~%" (solve2 input))
    
    3 votes
  11. [3]
    Gyrfalcon
    (edited )
    Link
    Language: Julia Repository Part 1 function main() # Read input the lazy way input = nothing open("Day06/input.txt") do fp input = split(readchomp(fp), "\n\n") end # Clean up input and map deploy...
    Part 1
    function main()
    
        # Read input the lazy way
        input = nothing
        open("Day06/input.txt") do fp
            input = split(readchomp(fp), "\n\n")
        end
    
        # Clean up input and map deploy our function
        answers = map(x -> split(x, '\n'), input)
        result_1 = sum(count_yes.(answers))
        println("Part 1 result is ", result_1)
    
    
    end
    
    # Add every answer to a set, unique yes answers are the length
    function count_yes(answer)
        questions = Set()
        for response in answer
            for question in response
                push!(questions, question)
            end
        end
        return length(questions)
    end
    
    main()
    
    Part 2 diff
    @@ -11,7 +11,8 @@ function main()
         result_1 = sum(count_yes.(answers))
         println("Part 1 result is ", result_1)
     
    -
    +    result_2 = sum(count_unanimous.(answers))
    +    println("Part 2 result is ", result_2)
     
     end
     
    @@ -26,4 +27,17 @@ function count_yes(answer)
         return length(questions)
     end
     
    +# Add answers from each person to a set and intersect to get unanimity
    +function count_unanimous(answer)
    +    clean_responses = []
    +    for response in answer
    +        clean_response = Set()
    +        for question in response
    +            push!(clean_response, question)
    +        end
    +        push!(clean_responses, clean_response)
    +    end
    +    return length(intersect(clean_responses...))
    +end
    +
     main()
    
    Ryzen 5 2600 vs Raspberry Pi 3b Performance include("Day06/main.jl")
    # Ryzen 5
    BenchmarkTools.Trial: 
      memory estimate:  13.08 MiB
      allocs estimate:  242404
      --------------
      minimum time:     154.777 ms (0.00% GC)
      median time:      164.188 ms (0.00% GC)
      mean time:        165.455 ms (1.37% GC)
      maximum time:     182.480 ms (4.63% GC)
      --------------
      samples:          31
      evals/sample:     1
    
    # Ras Pi
    BenchmarkTools.Trial:
      memory estimate:  13.08 MiB
      allocs estimate:  242385
      --------------
      minimum time:     1.090 s (0.00% GC)
      median time:      1.102 s (0.00% GC)
      mean time:        1.109 s (0.83% GC)
      maximum time:     1.144 s (4.02% GC)
      --------------
      samples:          5
      evals/sample:     1
    

    Overall an impressive showing for the Pi, given that it's max power is 12 times less than idle consumption on my desktop!

    Ryzen 5 2600 vs Raspberry Pi 3b Performance main() only
    # Ryzen 5
    BenchmarkTools.Trial: 
      memory estimate:  2.74 MiB
      allocs estimate:  36358
      --------------
      minimum time:     3.591 ms (0.00% GC)
      median time:      4.389 ms (0.00% GC)
      mean time:        4.484 ms (2.45% GC)
      maximum time:     10.671 ms (0.00% GC)
      --------------
      samples:          1116
      evals/sample:     1
    
    # Ras Pi
    BenchmarkTools.Trial: 
      memory estimate:  2.74 MiB
      allocs estimate:  36358
      --------------
      minimum time:     36.082 ms (0.00% GC)
      median time:      36.734 ms (0.00% GC)
      mean time:        38.169 ms (2.43% GC)
      maximum time:     57.162 ms (26.49% GC)
      --------------
      samples:          131
      evals/sample:     1
    
    3 votes
    1. [2]
      Liru
      Link Parent
      Uh, possibly stupid question, but what exactly are those benchmarks measuring? Taking over a second, even on an RPi, makes it seem like Julia is a ridiculously slow language... my relatively...

      Uh, possibly stupid question, but what exactly are those benchmarks measuring? Taking over a second, even on an RPi, makes it seem like Julia is a ridiculously slow language... my relatively inefficient C# code gets both solutions in ~45ms on an ancient overloaded laptop from a cold boot, so something seems off here.

      2 votes
      1. Gyrfalcon
        (edited )
        Link Parent
        Those benchmarks are measuring my lazy way of executing scripts that I am changing frequently from the REPL, which is to run include("Day06/main.jl"), which I think recompiles every time. Fine...

        Those benchmarks are measuring my lazy way of executing scripts that I am changing frequently from the REPL, which is to run include("Day06/main.jl"), which I think recompiles every time. Fine when I am writing code since I have to do that to run the function at the REPL anyway, definitely slower than one would expect if you were going to run the function many times though. If I do something more reasonable, like include the file and then just run main(), the results are much better:

        Ryzen 5 2600 vs Raspberry Pi 3b Performance main() only
        # Ryzen 5
        BenchmarkTools.Trial: 
          memory estimate:  2.74 MiB
          allocs estimate:  36358
          --------------
          minimum time:     3.591 ms (0.00% GC)
          median time:      4.389 ms (0.00% GC)
          mean time:        4.484 ms (2.45% GC)
          maximum time:     10.671 ms (0.00% GC)
          --------------
          samples:          1116
          evals/sample:     1
        
        # Ras Pi
        BenchmarkTools.Trial: 
          memory estimate:  2.74 MiB
          allocs estimate:  36358
          --------------
          minimum time:     36.082 ms (0.00% GC)
          median time:      36.734 ms (0.00% GC)
          mean time:        38.169 ms (2.43% GC)
          maximum time:     57.162 ms (26.49% GC)
          --------------
          samples:          131
          evals/sample:     1
        

        I'll add those results to my original comment and note the difference between the two. The performance impact is indicative of what I understand to be a pretty big issue in Julia development right now, which is often called the "first plot" problem. When you first bring in big packages, notably plotting packages, the whole thing has to be JIT compiled, which can make the first plot super slow, and then the subsequent plots come out quickly. There's some ways around it with caching compiled versions of packages as well as just improving the JIT compiler performance but it can still be pretty poky if you do stupid stuff like I was in those tests!

        2 votes
  12. wycy
    (edited )
    Link
    Rust Rust use std::env; use std::io; use std::collections::HashMap; extern crate itertools; use itertools::Itertools; fn day06(input: &str) -> io::Result<()> { // Part 1 let part1: usize =...

    Rust

    Rust
    use std::env;
    use std::io;
    use std::collections::HashMap;
    
    extern crate itertools;
    use itertools::Itertools;
    
    fn day06(input: &str) -> io::Result<()> {
        
        // Part 1
        let part1: usize = std::fs::read_to_string(input)
            .unwrap()
            .split("\n\n")
            .map(|group| group.replace("\n","").chars().unique().count())
            .sum();
    
        println!("Part 1: {}", part1); // 6532
    
        // Part 2
        let mut ans: Vec<HashMap<char,usize>> = Vec::new();
        let input_str = std::fs::read_to_string(input).unwrap();
        let answers: Vec<_> = input_str.split("\n\n").collect();
    
        let mut part2 = 0;
        for (i,group) in answers.iter().enumerate() {
            ans.push(HashMap::new());
            let group_size = &group.split("\n").collect::<Vec<_>>().len();
            for person in group.split("\n") {
                for a in person.chars() {
                    *ans[i].entry(a).or_insert(0) += 1;
                }
            }
            part2 += ans[i].iter().filter(|(_,v)| v == &group_size).count();
        }
    
        println!("Part 2: {}", part2); // 3427
    
        Ok(())
    }
    
    fn main() {
        let args: Vec<String> = env::args().collect();
        let filename = &args[1];
        day06(&filename).unwrap();
    }
    
    3 votes
  13. heady
    Link
    both parts rawinput = open("day6input", 'r') groups = [] form = {} group_count = 1 new_group = True for line in rawinput: if new_group == True: form['members'] = 0 groups.append(form) if len(line)...
    both parts
    rawinput = open("day6input", 'r')
    
    groups = []
    form = {}
    
    group_count = 1
    new_group = True
    
    for line in rawinput:
        if new_group == True:
            form['members'] = 0
            groups.append(form)
    
        if  len(line) == 1:
            group_count += 1
            new_group = True
            form = {}
        else:
            form['members'] = form['members'] + 1
            new_group = False
            for answer in line:
                if answer == '\n':
                    break
                if answer in form:
                    form[answer] = form[answer] + 1
                else:
                    form[answer] = 1
    
    group_sum = 0
    for form in groups:
        group_sum += len(form) - 1
    print(group_sum)
    
    unanimous_group_sum = 0
    for form in groups:
        unanimous_answers = -1
        for answer in form:
            if form[answer] == form['members']:
                unanimous_answers += 1
        unanimous_group_sum += unanimous_answers
    print(unanimous_group_sum)
    
    3 votes
  14. jzimbel
    (edited )
    Link
    All of my solutions have been in Elixir, and they all are just a pile of pipes, and I love it. 😁 I used this starter project, so my code expects the input to come in the form of a string argument...

    All of my solutions have been in Elixir, and they all are just a pile of pipes, and I love it. 😁

    I used this starter project, so my code expects the input to come in the form of a string argument to each of part1 and part2.

    Parts 1 and 2
    defmodule AdventOfCode.Day06 do
      def part1(args) do
        count_yeses(args, &group_to_union_set/1)
      end
    
      def part2(args) do
        count_yeses(args, &group_to_intersection_set/1)
      end
    
      defp count_yeses(input, set_builder) do
        input
        |> parse_groups()
        |> Enum.map(set_builder)
        |> Enum.map(&MapSet.size/1)
        |> Enum.sum()
      end
    
      defp parse_groups(input) do
        input
        |> String.trim()
        |> String.split("\n\n")
      end
    
      defp group_to_union_set(group) do
        group
        |> String.replace(~r|[^a-z]|, "")
        |> String.to_charlist()
        |> MapSet.new()
      end
    
      defp group_to_intersection_set(group) do
        group
        |> String.split()
        |> Enum.map(&String.to_charlist/1)
        |> Enum.map(&MapSet.new/1)
        |> Enum.reduce(&MapSet.intersection/2)
      end
    end
    
    Explanation

    Each part is solved by simply calling a count_yeses function that counts the total number of "yes" responses, given the following arguments: 1) the input string, and 2) a function1 that builds the appropriate set for each customs declaration.

    count_yeses takes the input, and pipes it through the following operations (think of this like an assembly line where each operation takes the result of the previous one):

    1. Split into separate strings for each group of people: string -> list(string)
    2. Apply the given set_builder function to each group: list(string) -> list(set)
    3. Get the number of elements in each set: list(set) -> list(integer)
    4. Sum everything up: list(integer) -> integer

    group_to_union_set collects all the characters in a single group and creates one set out of them. This is the same as creating a set for each line and then union-ing them all together.

    group_to_intersection_set puts the characters on each line of a group into a set, then intersects them together to get the overall intersection.

    1 In order to pass a named function rather than calling it in elixir, you need to use the & function capture operator. Functions are also distinguished by their arity (number of arguments taken), so you also need to include that to uniquely identify it: &function_name/arity.

    3 votes
  15. sal
    Link
    Short in Python Part 1 groupAnswersList = open('day6_input.txt').read().split('\n\n') print(sum([len(set(groupAnswers.replace('\n', ''))) for groupAnswers in groupAnswersList])) Part2...

    Short in Python

    Part 1
    groupAnswersList = open('day6_input.txt').read().split('\n\n')
    print(sum([len(set(groupAnswers.replace('\n', ''))) for groupAnswers in groupAnswersList]))
    
    Part2
    print(sum([len(set.intersection(*[ set(answers) for answers in groupAnswers.split('\n')])) for groupAnswers in groupAnswersList ]))
    
    3 votes
  16. spit-evil-olive-tips
    Link
    Part 1 As with my day 4 solution, I read the whole file into memory so I can split on \n\n, then convert each group of people into a list, where each person in the group is represented by a set of...
    Part 1

    As with my day 4 solution, I read the whole file into memory so I can split on \n\n, then convert each group of people into a list, where each person in the group is represented by a set of the questions they said yes to.

    Then, counting the number of questions that any person in a group said yes to is just the length of the union of all those sets:

    def parse_input(input_path):
        with open(input_path) as input_file:
            contents = input_file.read()
    
        groups = []
        for raw_group in contents.split('\n\n'):
            members = [set(line) for line in raw_group.strip().split('\n')]
            groups.append(members)
    
        return groups
    
    
    def main():
        groups = parse_input('006.txt')
    
        total_yes = 0
        for group in groups:
            combined = set.union(*group)
            total_yes += len(combined)
    
        print(total_yes)
    
    
    if __name__ == '__main__':
        main()
    
    Part 2

    And part 2 becomes a trivial change:

    --- 006a.py     2020-12-05 21:20:21.990382335 -0800
    +++ 006b.py     2020-12-05 21:20:08.591341695 -0800
    @@ -15,7 +15,7 @@
     
         total_yes = 0
         for group in groups:
    -        combined = set.union(*group)
    +        combined = set.intersection(*group)
             total_yes += len(combined)
     
         print(total_yes)
    
    2 votes
  17. blitz
    (edited )
    Link
    Rust use std::io; use std::io::prelude::*; use std::collections::{HashSet, HashMap}; fn group_lines(lines: &Vec<String>) -> Vec<Vec<String>> { let mut groups = Vec::new(); let mut current_group =...
    Rust
    use std::io;
    use std::io::prelude::*;
    
    use std::collections::{HashSet, HashMap};
    
    fn group_lines(lines: &Vec<String>) -> Vec<Vec<String>> {
        let mut groups = Vec::new();
    
        let mut current_group = Vec::new();
    
        for l in lines.iter() {
            if l.len() == 0 {
                groups.push(current_group);
                current_group = Vec::new();
            } else {
                current_group.push(l.clone());
            }
        }
    
        if current_group.len() > 0 {
            groups.push(current_group);
        }
    
        groups
    }
    
    fn unique_answers_in_group(group: &Vec<String>) -> usize {
        let mut hashset = HashSet::new();
    
        for line in group.iter() {
            for c in line.chars() {
                hashset.insert(c);
            }
        }
    
        hashset.len()
    }
    
    fn unanimous_answers_in_group(group: &Vec<String>) -> usize {
        let mut map = HashMap::new();
    
        for line in group.iter() {
            for c in line.chars() {
                if let Some(x) = map.get_mut(&c) {
                    *x = *x + 1;
                } else {
                    map.insert(c, 1);
                }
            }
        }
    
        map
            .iter()
            .filter(|(_, v)| **v == group.len())
            .map(|(k, _)| k)
            .count()
    }
    
    
    fn main() {
        let stdin = io::stdin();
        let lines: Vec<String> = stdin
            .lock()
            .lines()
            .collect::<Result<_, _>>()
            .unwrap();
    
        let grouped_lines = group_lines(&lines);
    
        let part1_ans: usize = grouped_lines
            .iter()
            .map(unique_answers_in_group)
            .sum();
        let part2_ans: usize = grouped_lines
            .iter()
            .map(unanimous_answers_in_group)
            .sum();
    
        println!("Part 1: {}", part1_ans);
        println!("Part 2: {}", part2_ans);
    }
    
    2 votes