Day 1: Historian Hysteria

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://blocks.programming.dev/ if you prefer sending it through a URL

FAQ

  • Quant@programming.dev
    link
    fedilink
    arrow-up
    1
    ·
    edit-2
    5 days ago

    Uiua

    Decided to try and use Uiua for each day this year. At least I’m not the only one to get this idea ^^

    Run with example input here

    PartOne ← (
      &rs ∞ &fo "input-1.txt"
      ⊜(⊜⋕≠@ .)≠@\n.
      ≡⍆⍉
      ⌵/-
      /+
    )
    
    PartTwo ← (
      &rs ∞ &fo "input-1.txt"
      ⊜(⊜⋕≠@ .)≠@\n.
      ⊢⟜⊣⍉
      0
      ⍢(+⊙(:⊙(×⧻⊚◡⌕)↘1⟜⊢)|⋅(≠0⧻))
      ⊙(◌◌) # just cleaning up the stack
    )
    
    &p "Day 1:"
    &pf "Part 1: "
    &p PartOne
    &pf "Part 2: "
    &p PartTwo
    
    
  • aurele@sh.itjust.works
    link
    fedilink
    arrow-up
    1
    ·
    6 days ago

    Elixir

    defmodule AdventOfCode.Solution.Year2024.Day01 do
      use AdventOfCode.Solution.SharedParse
    
      @impl true
      def parse(input) do
        numbers =
          input
          |> String.split("\n", trim: true)
          |> Enum.map(fn l -> String.split(l, ~r/\s+/) |> Enum.map(&String.to_integer/1) end)
    
        {Stream.map(numbers, &Enum.at(&1, 0)), Stream.map(numbers, &Enum.at(&1, 1))}
      end
    
      def part1({left, right}) do
        Enum.zip_reduce(Enum.sort(left), Enum.sort(right), 0, &(&3 + abs(&1 - &2)))
      end
    
      def part2({left, right}) do
        freq = Enum.frequencies(right)
        left |> Stream.map(&(&1 * Map.get(freq, &1, 0))) |> Enum.sum()
      end
    end
    
  • mykl@lemmy.world
    link
    fedilink
    arrow-up
    7
    ·
    edit-2
    11 days ago

    Uiua

    For entertainment purposes only, I’ll be trying a solution in Uiua each day until it all gets too much for me…

    $ 3   4
    $ 4   3
    $ 2   5
    $ 1   3
    $ 3   9
    $ 3   3
    ⊜∘⊸≠@\n     # Partition at \n.
    ⊜(⍆∵⋕)⊸≠@\s # Partition at space, parse ints, sort.
    
    &p/+/(⌵-). # Part1 : Get abs differences, sum, print.
    
    &p/+×⟜(/+⍉≡⌕)°⊂ # Part 2 : Count instances, mul out, sum, print.
    
  • lwhjp@lemmy.sdf.org
    link
    fedilink
    arrow-up
    6
    ·
    11 days ago

    Haskell

    Plenty of scope for making part 2 faster, but I think simple is best here. Forgot to sort the lists in the first part, which pushed me waaay off the leaderboard.

    import Data.List
    
    main = do
      [as, bs] <- transpose . map (map read . words) . lines <$> readFile "input01"
      print . sum $ map abs $ zipWith (-) (sort as) (sort bs)
      print . sum $ map (\a -> a * length (filter (== a) bs)) as
    
  • Gobbel2000@programming.dev
    link
    fedilink
    arrow-up
    4
    ·
    11 days ago

    Rust

    Right IDs are directly read into a hash map counter.

    use std::str::FromStr;
    use std::collections::HashMap;
    
    fn part1(input: String) {
        let mut left = Vec::new();
        let mut right = Vec::new();
        for line in input.lines() {
            let mut parts = line.split_whitespace()
                .map(|p| u32::from_str(p).unwrap());
            left.push(parts.next().unwrap());
            right.push(parts.next().unwrap());
        }
        left.sort_unstable();
        right.sort_unstable();
        let diff: u32 = left.iter().zip(right)
            .map(|(l, r)| l.abs_diff(r))
            .sum();
        println!("{diff}");
    }
    
    fn part2(input: String) {
        let mut left = Vec::new();
        let mut right: HashMap<u32, u32> = HashMap::new();
        for line in input.lines() {
            let mut parts = line.split_whitespace()
                .map(|p| u32::from_str(p).unwrap());
            left.push(parts.next().unwrap());
            *right.entry(parts.next().unwrap()).or_default() += 1;
        }
        let similar: u32 = left.iter()
            .map(|n| n * right.get(n).copied().unwrap_or_default())
            .sum();
        println!("{similar}");
    }
    
    util::aoc_main!();
    
  • janAkali@lemmy.one
    link
    fedilink
    English
    arrow-up
    4
    ·
    edit-2
    11 days ago

    Nim

    I’ve got my first sub-1000 rank today (998 for part 2). Yay!
    Simple and straightforward challenge, very fitting for 1st day. Gonna enjoy it while it lasts.

    proc solve(input: string): AOCSolution[int, int] =
      var l1,l2: seq[int]
      for line in input.splitLines():
        let pair = line.splitWhitespace()
        l1.add parseInt(pair[0])
        l2.add parseInt(pair[1])
      l1.sort()
      l2.sort()
    
      block p1:
        for i in 0..l1.high:
          result.part1 += abs(l1[i] - l2[i])
    
      block p2:
        for n in l1:
          result.part2 += n * l2.count(n)
    

    Codeberg repo

  • Rin@lemm.ee
    link
    fedilink
    arrow-up
    4
    ·
    edit-2
    11 days ago

    TypeScript

    Solution
    import { AdventOfCodeSolutionFunction } from "./solutions";
    
    function InstancesOf(sorted_array: Array<number>, value: number) {
        const index = sorted_array.indexOf(value);
        if(index == -1)
            return 0;
    
        let sum = 1;
    
        for (let array_index = index + 1; array_index < sorted_array.length; array_index++) {
            if(sorted_array[array_index] != value)
                break;
    
            sum += 1;
        }
    
        return sum;
    }
    
    export const solution_1: AdventOfCodeSolutionFunction = (input) => {
        const left: Array<number> = [];
        const right: Array<number> = [];
    
        const lines = input.split("\n");
    
        for (let index = 0; index < lines.length; index++) {
            const element = lines[index].trim();
            if(!element)
                continue;
    
            const leftRight = element.split("   ");
            left.push(Number(leftRight[0]));
            right.push(Number(leftRight[1]));
        }
    
        const numSort = (a: number, b: number) => a - b;
        left.sort(numSort);
        right.sort(numSort);
    
        let sum = 0;
        for (let index = 0; index < left.length; index++) {
            const leftValue = left[index];
            const rightValue = right[index];
    
            sum += Math.abs(leftValue - rightValue);
        }
    
        const part1 = `Part 1: ${sum}`;
    
        sum = 0;
        for (let index = 0; index < left.length; index++) {
            sum += left[index] * InstancesOf(right, left[index]);
        }
    
        const part2 = `Part 2: ${sum}`;
    
        return `${part1}\n${part2}`;
    };
    

    Not the most elegant solution but it works. Decided to reuse the array since it is sorted for both sides.

  • MalachiAzrael@sh.itjust.works
    link
    fedilink
    English
    arrow-up
    3
    ·
    11 days ago

    Python

    Part 1
    left_list = []
    right_list = []
    
    for line in file:
        split_line = line.split()
        left_list.append(int(split_line[0]))
        right_list.append(int(split_line[1]))
    
    sorted_left = sorted(left_list)
    sorted_right = sorted(right_list)
    distance = []
    for left, right in zip(sorted_left, sorted_right):
        distance.append(abs(left - right))
    
    total = sum(distance)
    
    print(total)
    
    Part 2
    file = open('input.txt', 'r')
    left_list = []
    right_list = []
    
    for line in file:
        split_line = line.split()
        left_list.append(int(split_line[0]))
        right_list.append(int(split_line[1]))
    
    sim_score = 0
    for item in left_list:
        sim = right_list.count(item)
        sim_score += (sim * item)
    
    print(sim_score)
    

    I am sure there were better ways to do this, this was just the first way in my head, in the order it appeared

  • Leavingoldhabits@lemmy.world
    link
    fedilink
    arrow-up
    3
    ·
    11 days ago

    I’m quite inexperienced as a programmer, I learned most of the basic concepts from playing human resource machine and 7 billion humans. After mucking about writing some CLI utilities in Perl and python, I’ve decided to give rust a go.

    Part 1

    Part 2

  • Ananace@lemmy.ananace.dev
    link
    fedilink
    arrow-up
    3
    ·
    11 days ago

    Not going to push hard on these first days (fever being a reason), so I slept in quite a bit before looking at the problem.

    C#
    List<int> _LeftList = new List<int>();
    List<int> _RightList = new List<int>();
    
    // Fed via File.ReadLines(...).Select(l => l.Trim())
    public void Input(IEnumerable<string> lines)
    {
      foreach (var line in lines)
      {
        var split = line.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(s => int.Parse(s));
        _LeftList.Add(split.First());
        _RightList.Add(split.Last());
      }
    }
    
    public void Part1()
    {
      Console.WriteLine($"Sum: {_LeftList.Order().Zip(_RightList.Order()).Select(v => Math.Abs(v.First - v.Second)).Sum()}");
    }
    public void Part2()
    {
      Console.WriteLine($"Sum: {_LeftList.Select(l => _RightList.Where(i => i == l).Count() * l).Sum()}");
    }
    
  • proved_unglue@programming.dev
    link
    fedilink
    arrow-up
    3
    ·
    9 days ago

    Kotlin

    No 💜 for Kotlin here?

    import kotlin.math.abs
    
    fun part1(input: String): Int {
        val diffs: MutableList<Int> = mutableListOf()
        val pair = parse(input)
        pair.first.sort()
        pair.second.sort()
        pair.first.forEachIndexed { idx, num ->
            diffs.add(abs(num - pair.second[idx]))
        }
        return diffs.sum()
    }
    
    fun part2(input: String): Int {
        val pair = parse(input)
        val frequencies = pair.second.groupingBy { it }.eachCount()
        var score = 0
        pair.first.forEach { num ->
            score += num * frequencies.getOrDefault(num, 0)
        }
        return score
    }
    
    private fun parse(input: String): Pair<MutableList<Int>, MutableList<Int>> {
        val left: MutableList<Int> = mutableListOf()
        val right: MutableList<Int> = mutableListOf()
        input.lines().forEach { line ->
            if (line.isNotBlank()) {
                val parts = line.split("\\s+".toRegex())
                left.add(parts[0].toInt())
                right.add(parts[1].toInt())
            }
        }
        return left to right
    }
    
    • the_beber@lemm.ee
      link
      fedilink
      English
      arrow-up
      1
      ·
      edit-2
      8 days ago

      I have another Kotlin (albeit similar) solution:

      import kotlin.math.abs
      
      fun main() {
      
          fun getLists(input: List<String>): Pair<List<Int>, List<Int>> {
              val unsortedPairs = input.map {
                  it.split("   ").map { it.toInt() }
              }
      
              val listA = unsortedPairs.map { it.first() }
              val listB = unsortedPairs.map { it.last() }
              return Pair(listA, listB)
          }
      
          fun part1(input: List<String>): Int {
              val (listA, listB) = getLists(input)
      
              return listA.sorted().zip(listB.sorted()).sumOf { abs(it.first - it.second) }
          }
      
          fun part2(input: List<String>): Int {
              val (listA, listB) = getLists(input)
      
              return listA.sumOf { number ->
                  number * listB.count { it == number }
              }
          }
      
          // Or read a large test input from the `src/Day01_test.txt` file:
          val testInput = readInput("Day01_test")
          check(part1(testInput) == 11)
          check(part2(testInput) == 31)
      
          // Read the input from the `src/Day01.txt` file.
          val input = readInput("Day01")
          part1(input).println()
          part2(input).println()
      }
      
      

      It’s a bit more compact. (If you take out the part that actually calls the functions on the (test-)input.)

      • proved_unglue@programming.dev
        link
        fedilink
        arrow-up
        1
        ·
        8 days ago

        Thanks! I like the Pair destruction and zip().sumOf() approach. I’m relatively new to Kotlin, so this is a good learning experience. 😅

  • sjmulder@lemmy.sdf.org
    link
    fedilink
    arrow-up
    3
    ·
    11 days ago

    Solution in C

    Part 1 is a sort and a quick loop. Part 2 could be efficient with a lookup table but it was practically instant with a simple non-memoized scan so left it that way.

    • mcmodknower@programming.dev
      link
      fedilink
      English
      arrow-up
      1
      ·
      edit-2
      11 days ago

      You are using some interesting techniques there. I never imaged you could use the result of == for adding to a counter.

      But how did you handle duplicates in part 2?

      • sjmulder@lemmy.sdf.org
        link
        fedilink
        arrow-up
        1
        ·
        11 days ago

        I’m not sure if I understand the question correctly but for every number in the left array I count in the right array. That means duplicate work but shrug 😅

  • hades@lemm.ee
    link
    fedilink
    arrow-up
    3
    ·
    11 days ago

    C#

    public class Day01 : Solver
    {
      private ImmutableArray<int> left;
      private ImmutableArray<int> right;
    
      public void Presolve(string input)
      {
        var pairs = input.Trim().Split("\n").Select(line => Regex.Split(line, @"\s+"));
        left = pairs.Select(item => int.Parse(item[0])).ToImmutableArray();
        right = pairs.Select(item => int.Parse(item[1])).ToImmutableArray();
      }
    
      public string SolveFirst() => left.Sort().Zip(right.Sort()).Select((pair) => int.Abs(pair.First - pair.Second)).Sum().ToString();
    
      public string SolveSecond() => left.Select((number) => number * right.Where(v => v == number).Count()).Sum().ToString();
    }
    
  • morrowind@lemmy.ml
    link
    fedilink
    arrow-up
    3
    ·
    10 days ago

    Smalltalk

    day1p12: input    
    	| list1 list2 nums dist sim |
    	
    	list1 := OrderedCollection new.
    	list2 := OrderedCollection new.
    	
    	input linesDo: [ :l |
    		nums := l substrings collect: [ :n | n asInteger ].
    		list1 add: (nums at: 1).
    		list2 add: (nums at: 2).
    	].
    
    	list1 sort.
    	list2 sort.
    	
    	dist := 0.
    	list1 with: list2 do: [ :a :b | dist := dist + (a - b) abs ].
    	
    	sim := list1 sumNumbers: [ :x | x * (list2 occurrencesOf: x) ].
    	
    	^ Array with: dist with: sim.
    
  • vole@lemmy.world
    link
    fedilink
    English
    arrow-up
    2
    ·
    edit-2
    10 days ago

    Raku

    I’m trying warm up to Raku again.

    Solution

    github

    use v6;
    
    sub MAIN($input) {
        my $file = open $input;
    
        grammar LocationList {
            token TOP { <row>+%"\n" "\n"* }
            token row { <left=.id> " "+ <right=.id> }
            token id { \d+ }
        }
    
        my $locations = LocationList.parse($file.slurp);
        my @rows = $locations<row>.map({ (.<left>.Int, .<right>.Int)});
        my $part-one-solution = (@rows[*;0].sort Z- @rows[*;1].sort)».abs.sum;
        say "part 1: $part-one-solution";
    
        my $rbag = bag(@rows[*;1].sort);
        my $part-two-solution = @rows[*;0].map({ $_ * $rbag{$_}}).sum;
        say "part 2: $part-two-solution";
    }
    

    I’m happy to see that Lemmy no longer eats Raku code.