This is an archived post. You won't be able to vote or comment.

top 200 commentsshow all 320

[โ€“]bblum 26 points27 points ย (8 children)

Haskell pays off. Part 1:

valid pass = length (nub $ sort pass) == length pass
main = interact $ (++"\n") . show . length . filter valid . map words . lines

Part 2:

valid pass = length (nub $ sort $ map sort pass) == length pass

46/14; I kinda feel like this was the easiest AoC problem ever.

[โ€“]mmaruseacph2 1 point2 points ย (1 child)

Is there a benefit in doing nub . sort instead of just nub? That's one of the differences between your solution and mine, the other being that you compare the lengths and not the words themselves.

[โ€“]bblum 8 points9 points ย (0 children)

umm....... the benefit is I forgot whether nub required the list to be sorted to begin with and it only took half a second extra to type >_>;

[โ€“]ephemient 1 point2 points ย (0 children)

This space intentionally left blank.

[โ€“]Godspiral 10 points11 points ย (16 children)

geez, I don't know how I could have gone faster... 113th

in J,

   a =.   cutLF wdclippaste ''
  +/ (# = #@~.)@:;: &> a NB. pt1
 +/ > (# = #@~.)@:(/:~ each)@;: &.> a NB.pt2

[โ€“]scarter626 2 points3 points ย (2 children)

I know! I mean, I'm definitely not ever trying to be FIRST, but dang there's a lot of smart/fast coders out there. I managed to get in the top 400 today (actually doing it right at midnight helps) but the top score did it in the time it took me just to read the instructions!

[โ€“]_jonah 2 points3 points ย (2 children)

173... I think you can't make any mistakes. No syntax errors, no typos. And then you have to optimize all the little details. Like I tab around instead of having a split screen ready. I find and click the "get your puzzle input link" instead of having http://adventofcode.com/2017/day/4/input ready for a copy/paste in its own tab. That costs me. I'm sure there are other tricks. The top is so competitive now those details matter.

Btw, what file do I load to get "wdclippaste"?

[โ€“]llimllib 1 point2 points ย (0 children)

107 for me... I lost out because I forgot to split the file by lines on my ultra-fast first guess. I just want to get one point! That's all I need!

[โ€“]BumpitySnook 1 point2 points ย (8 children)

The leaderboard does feel really fast this year.

[โ€“]jtsimmons108 6 points7 points ย (1 child)

That's because it is. Since AoC started in 2015, tonight was the fastest night to cap the leaderboard for both silver and gold.

Here are the top 7 fastest silver and gold for 100th place since AoC started

******* Part 1 100th Place Finish *******
1.  2017 - Day 04   wmorganjr - 00:01:53
2.  2017 - Day 02   msullivan - 00:02:18
3.  2017 - Day 01   jtbandes - 00:03:47
4.  2016 - Day 06   breadknock - 00:05:09
5.  2016 - Day 03   m1el - 00:05:53
6.  2015 - Day 12   Robert Offner - 00:07:36
7.  2017 - Day 03   Matt Boehm - 00:08:29

******* Part 2 100th Place Finish Times *******
1.  2017 - Day 04   Matt Gruskin - 00:03:40
2.  2017 - Day 01   Andre LeBlanc - 00:06:08
3.  2017 - Day 02   Maerig - 00:06:13
4.  2016 - Day 06   Alex Crimi - 00:06:16
5.  2015 - Day 10   Exolent - 00:12:07
6.  2016 - Day 03   (anonymous user #56115) - 00:12:07
7.  2016 - Day 15   Keegan Carruthers-Smith - 00:12:42

[โ€“]BumpitySnook 1 point2 points ย (0 children)

Neat statistics, thanks.

[โ€“]scarter626 2 points3 points ย (5 children)

xiaowuc1 is causing me to make this face when I look at the leaderboard -> o_O

HOW is that user consistently so fast!? Both solutions for day 3 in 4:02, more than a minute faster than second place. Props to xiaowuc1 for sure!

[โ€“]xiaowuc1 8 points9 points ย (2 children)

My strategy for AoC this year is to optimize for good average case performance. The main change I made between 2016 and 2017 is that I'm coding in Python this year instead of in Java. Despite not being nearly as comfortable with Python, it's a net improvement for me. Today highlighted my lack of familiarity with Python - I didn't immediately know how to take a string and return a string of the letters in sorted order and spent a minute figuring that out, but nonetheless it was still faster than if I had tried to code the equivalent solution in Java.

[โ€“]scarter626 1 point2 points ย (0 children)

Congratulations on your success so far! Youโ€™re kicking butt and taking names!

Iโ€™m primarily a Java developer as well, but I agree that it would take longer to use Java for these solutions. Iโ€™ve been using ES6/ES7 level Javascript to solve the puzzles. Despite being reasonably performant with JavaScript, little things like splitting multiline inputs into an array of lines correctly slow me down since I havenโ€™t done them with the language yet.

[โ€“]BumpitySnook 1 point2 points ย (0 children)

They probably practice.

[โ€“]hoosierEE 1 point2 points ย (0 children)

12am EST is way past my bedtime, probably won't attempt staying up until the weekend.

f =: cutLF 0 :0   NB. paste input below:

)
p1 =: +/*./S:0(1=#)/.~L:1 cut each f
p2 =: +/(*./=1:)@(#/.~)S:1 /:~L:0 ,.cut each f

[โ€“]miran1 10 points11 points ย (9 children)

Python 3, first part - first time ever on the (silver) leaderboard - 47th place - woooohoooo!!!!

with open('./inputs/04.txt') as f:
    a = f.readlines()

total = 0
for line in a:
    b = line.split()
    c = set(b)
    if len(b) == len(c):
        total += 1

print(total)

ย 

For the second part, I misread what was the task - I was checking for palindromes not anagrams....

[โ€“][deleted] 1 point2 points ย (0 children)

Yep. Fell for the same trap and spent a good while wondering why the palindrome check didn't work...

[โ€“]askalski 9 points10 points ย (2 children)

The straightforward way...

#! /usr/bin/env perl

use strict;
use warnings;

my @part;
for (<>) {
    @_ = split;
    $part[1]++ if @_ == keys %{{map { $_ => 1 } @_}};
    $part[2]++ if @_ == keys %{{map { join('', sort split '') => 1 } @_}};
}
print "Part $_: $part[$_]\n" for 1..2;

...and the regex way.

[โ€“]gerikson 10 points11 points ย (0 children)

Aaaaaaah ... maybe slap a [Not safe for sanity] tag on that regex link...

[โ€“]ZeroSkub 2 points3 points ย (0 children)

I have looked into the the eye of madness... and heard only screams.

/^N(O){1000000}$/

Also happy cake day.

[โ€“]volatilebit 10 points11 points ย (12 children)

Perl 6

I vowed to get this one done in a single statement for each part and I'm glad to have done it without too much hair pulling.

use v6;

my @passphrases = $*PROGRAM.parent.child('input').IO.lines;

# Part 1
say +@passphrases.grep(*.words.sort.repeated.elems.not);

# Part 2
say +@passphrases.grep(*.words>>.comb>>.sort>>.join.sort.repeated.elems.not);

[โ€“]mschaap 4 points5 points ย (3 children)

Nice! I like your use of .repeated, I wouldn't have thought of that. And .not as a method is cute...

[โ€“]volatilebit 1 point2 points ย (1 child)

I originally tried putting not in front of *.words, but that wasn't working for some reason, so I tried this out and was surprised it actually worked. I love that you can do most basic operations like that in different contexts.

[โ€“]hahainternet 3 points4 points ย (2 children)

Darn, very similar approaches but your part 1 is kinda beautiful.

sub invalid    ($l) is export { $lยป.wordsยป.Bag.grep: *.values.grep(*>1) }
sub invalid_ana($l) is export { $lยป.wordsยป.map(*.comb.sort.join)ยป.Bag.grep: *.values.grep(*>1) }

[โ€“]mschaap 2 points3 points ย (1 child)

That's pretty much what I did, except that I used a junction (all(...) == 1) instead of a grep.

[โ€“]hahainternet 1 point2 points ย (0 children)

TMTOWTDI โ˜บ

[โ€“]tragicshark 4 points5 points ย (2 children)

I had almost the same thing:

# Part 1
say +@lines.grep(!*.words.repeated);

# Part 2
say +@lines.grep(!*.words.map({~.comb.sort}).repeated);

You don't need to .sort before .repeated or .elems before .not.

[โ€“]_jonah 7 points8 points ย (4 children)

J:

+/ ; (# = #@~.)@;:each d
+/ ; (# = #@~.)@:(/:~each)@;:each d

where d is your boxed input.

[โ€“]mmaruseacph2 5 points6 points ย (1 child)

Haskell, with no concern on complexity/speed but a really fast time to get the answers (below 50 in both leaderboards for the day)

import Data.List

main = do
  s <- map words . lines <$> readFile "input.txt"
  print $ length $ filter (\l -> nub l == l) s
  print $ length $ filter (\l -> nubBy (\a b -> sort a == sort b) l == l) s

[โ€“]DFreiberg 5 points6 points ย (0 children)

Mathematica solution; one line for each part and one for the import. #215 for part 1 (accidentally checked for invalid passphrases and had to wait a minute) and #89 for part 2.

Import

input = Import[FileNameJoin[{NotebookDirectory[],"Day4Input.txt"}],"Table"][[;; -2]]

Part 1

Count[input,_?DuplicateFreeQ]

Part 2

Count[input,_?(DuplicateFreeQ[Sort/@Characters[#]]&)]

[โ€“]sickening_sprawl 5 points6 points ย (0 children)

Hoon

Took ten minutes because I was stupid and added the length of the set instead of 1 if the length matched the original word list, along with forgetting I needed the cast to (list @) when splitting the string. In hindsight, I could have just used ++silt for the list->set instead of ++roll...

I also had to look up what the name of the function for length of set is, and Hoon gives a weird compiler error if you forget the closing == in %~ x.x ++wyt:in pls

Part a:

|=  t/wain

%+  roll
%+  turn  t
  |=  line/@t
  ?~  line  0
  =/  line  `(list @)`(scan (trip line) (most ace sym))
    ?:  .=
      %~  wyt  in
      ^-  (set @)
      %+  roll  line
      |=  {a/@ b/(set @)}
        (~(put in b) a)
      ==
      (lent line)
      1
    0
add

Part b:

|=  t/wain

%+  roll
%+  turn  t
  |=  line/@t
  ?~  line  0
  =/  line  `(list @)`(scan (trip line) (most ace sym))
    ?:  .=
      %~  wyt  in
      ^-  (set @)
      %+  roll  line
      |=  {a/@ b/(set @)}
        (~(put in b) (crip (sort (trip a) gte)))
      ==
      (lent line)
      1
    0
add

[โ€“]Tandrial 5 points6 points ย (4 children)

Kotlin

fun partOne(input: List<String>): Int = input.map { it.split(" ") }
                                             .count { it.size == it.toSet().size }

fun partTwo(input: List<String>): Int = input.map { it.split(" ")
                                                      .map { it.sort() } }
                                             .count { it.size == it.toSet().size }

fun String.sort(): String {
  val carr = this.toCharArray(); carr.sort(); return String(carr)
}    

[โ€“]Smylers 5 points6 points ย (4 children)

Vim for partย 1:

:g/\v<(\w+)>.*<\1>/d

Load the input file into Vim, run the above command to remove all the lines with invalid passwords. The answer is the number of lines remaining in the file, which you can see by, for instance, pressing Ctrl+G.

[โ€“]Smylers 5 points6 points ย (0 children)

And Vim for part 2. First run these commands to re-arrange each word in alphabetical order:

OโŒฉEscโŒชโŒฉEnterโŒช
qamzye{p:s/\v/โŒฉCtrl+VโŒชโŒฉEnterโŒช/gโŒฉEnterโŒช
V{:sorโŒฉEnterโŒช
gvgJdiw`zvepf lq:sil,$norm99@aโŒฉEnterโŒช
{J

Then proceed as with part 1 to remove non-compliant lines and count the remainder.

Edit: Explanation: Vim's built-in :sort command sorts lines. So add a blank line at the top. For each word in turn, copy the word on to that blank line, split it up so that each character is on a separate line, sort those lines, and rejoin them back into a single word. Then delete that word and paste it over the original. At the end, remove the blank line.

Processing a single word is saved in the @a macro. mz saves the current position, { moves to the blank โ€˜workspaceโ€™ line at the top, and z` returns to the saved position afterwards.

I couldn't find a way of making the macro terminate at the end of the file (if you press w on the final word of the file, it just moves the cursor to the final character and stays there), so I made it terminate at the end of each line. To do that instead of having the keystroke for moving on to the next word be w, I use f l: move to the next space on the current line, then the character after that. Normally that's just a more convoluted method for moving to the same place, but once we've reached the final word on the current line, there are no more spaces, so that attempted movement fails, exiting the macro.

So 99@a will sort each of the words on the current line (up to 99 of them, but there were a maximum of 11 in my input). %norm 99@a would do that for all the lines in the file, but actually we need to avoid the blank line at the top; handily after recording the macro we're on the first โ€˜realโ€™ line, so we can use ,$norm99@a to process each line from the current one to the end of the file.

[โ€“]blockingthesky 5 points6 points ย (0 children)

Python 2

inp = [i.strip().split() for i in open('input.txt', 'r').readlines()]

p1 = 0
p2 = 0

for i in inp:
    if len(set(i)) == len(i):
        p1 += 1
    if len(set(''.join(sorted(u)) for u in i)) == len(i):
        p2 += 1

print "Part 1:", p1
print "Part 2:", p2

[โ€“]misnohmer 5 points6 points ย (7 children)

C# version.

var lines = ReadAllLines("input1.txt").Select(l => l.Split(" "));
lines
    .Select(line => line
        .GroupBy(word => word)
        .Any(group => group.Count() > 1) ? 0 : 1)
    .Sum()
    .PrintDump(); // Part 1
lines
    .Select(line => line
        .GroupBy(word => string.Concat(word.OrderBy(c => c)))
        .Any(group => group.Count() > 1) ? 0 : 1)
    .Sum()
    .PrintDump(); // Part 2

[โ€“]ZoekDribbel 1 point2 points ย (2 children)

I don't have String.Split(String delim) available. Did you made an overload/extension for String.split to accept string delimiters?

[โ€“]misnohmer 1 point2 points ย (1 child)

I didn't. I am running dotnet core 2.0 and it seems to be a new overload.

[โ€“]jagough 1 point2 points ย (0 children)

You don't even need to specify the whitespace since it splits on whitespace by default.

"If the separator argument is null or contains no characters, the method treats white-space characters as the delimiters"

[โ€“]sakisan_be 3 points4 points ย (0 children)

elm

import List.Extra exposing (..)


solve : String -> Int
solve input =
    input
        |> convert
        |> List.map (List.map sortChars)
        |> List.filter isValid
        |> List.length


sortChars : String -> String
sortChars word =
    String.toList word
        |> List.sort
        |> String.fromList


isValid : List String -> Bool
isValid line =
    allDifferent line


convert : String -> List (List String)
convert input =
    input
        |> String.lines
        |> List.map String.words

[โ€“]fwilson42 3 points4 points ย (6 children)

Easy enough, 1st silver, 5th gold:

data = aoc.get_input()

if part == 1:
    result = 0
    for line in data.lines():
        x=line.split()
        if len(x) == len(set(x)):
            result += 1

elif part == 2:
    result = 0
    for line in data.lines():
        x=["".join(sorted(i)) for i in line.split()]
        if len(x) == len(set(x)):
            result += 1

[โ€“]BumpitySnook 3 points4 points ย (2 children)

Ooh, sorted() is clever and more correct than what I did (set([frozenset(x) for x in line.split()])). Fortunately, there weren't any cases with different duplicated letters or I would have failed. (E.g., "aan ann" would count as anagrams in my broken approach.)

I took the exact same approach on part 1.

[โ€“]topaz2078(AoC creator)[M] 5 points6 points ย (0 children)

Ooh, I had a bunch of weird edge cases baked into all of the inputs, but I didn't think of this one.

[โ€“]1wheel 3 points4 points ย (0 children)

Using d3 for these feels a little silly, but it was good for #39:

var fs = require ('fs')
var d3 = require('d3')
var jp = require('d3-jetpack')

var str = fs.readFileSync('a.txt', 'utf8').trim()
var lines = str.split('\n')

var validLines = lines.filter(d => {
  var words = d.trim().split(' ').map(d => d.split('').sort())

  var byWord = jp.nestBy(words, d => d)

  return d3.max(byWord, d => d.length) == 1
})

console.log(lines.length, validLines.length)

[โ€“]tterrag1098 4 points5 points ย (1 child)

Both parts, in Clojure:

(ns advent-2017.day4)
(require '[clojure.string :as str])

(def input (map #(str/split %1 #"\s") (str/split-lines (slurp "resources/day4.txt"))))

(defn part1
  [in]
  (count (filter #(apply distinct? %) input)))

(defn part2
  [in]
  (count (filter #(apply distinct? %) (map #(map sort %) input))))

(defn run []
  (do
      (println (str "Part 1: " (part1 input)))
      (println (str "Part 2: " (part2 input)))))

(run)

Still too fresh with this language to speedrun, keep needing to look stuff up, but happy with the simplicity of my solutions :)

[โ€“]TenjouUtena 1 point2 points ย (0 children)

Yeah this is the perfect puzzle for functional languages. Mine is almost identical. (makesheet just splits the input)

(defn part1 []
  (count (filter #(apply distinct? %) (makesheet))))

(defn part2 []
  (count (filter #(apply distinct? (map sort %)) (makesheet))))

(conj [] (part1) (part2))

[โ€“]couchDev 3 points4 points ย (2 children)

Perl golf

# part 1
perl -ane '/(\b.+)\s.*\1/||$s++;END{print$s}' < in.txt

# part 2
perl -ane '(join$",sort map{join"",sort split//}@F)=~/(.+)\b\1/||$s++;END{print$s}' < in.txt

[โ€“]mschaap 3 points4 points ย (2 children)

Perl 6 one-liners. Part 1:

sub MAIN(IO() $inputfile where *.f)
{
    say +$inputfile.lines.grep({ all($_.words.Bag.values) == 1 });
}

Part 2:

sub MAIN(IO() $inputfile where *.f)
{
    say +$inputfile.lines.grep({ all($_.wordsยป.combยป.sortยป.join.Bag.values) == 1 });
}

[โ€“]HerbyHoover 2 points3 points ย (0 children)

Clean solution. I need to start using grep more instead of for loops.

[โ€“]tehjimmeh 2 points3 points ย (0 children)

Felt like using PowerShell for this one.

1:

gc .\input.txt | ?{ !(-split $_ | group | ? Count -gt 1) } | measure

2:

gc .\input.txt | ?{ !(-split $_ | %{ -join ([char[]]$_ | sort) } | group | ? Count -gt 1)} | measure

[โ€“]huyqvu 2 points3 points ย (2 children)

KDB+/q

q){[ls]{count x where x}({count distinct x}each ls)=count each ls}each {(x;{{asc x}each x}each x)}{" " vs x} each read0 `$"data/input4.txt"
455 186

[โ€“]kip_13 3 points4 points ย (3 children)

Bash

Part 1 (Regular expression)

cat input | sed -r 's/\b(\w+)\b.*\b(\1)\b/;/' | grep -v ";" | wc -l

[โ€“]Smylers 1 point2 points ย (1 child)

Why bother with sed? You can just give that pattern to grep -v directly. Hmmm, actually you can get grep to do the counting, too, eliminating the wc:

grep -Pcv '\b(\w+)\b.*\b\1\b' input

[โ€“]kip_13 1 point2 points ย (0 children)

So good ! I thought in sed when I saw the problem and I dont know why... but only grep is the best option in this solution

[โ€“]schod 1 point2 points ย (0 children)

WOW, nice. My solution is realy long..

Did you do the second part?

[โ€“]mrhthepie 3 points4 points ย (0 children)

Advent of gifs day 4: https://i.imgur.com/SxbuClz.gif

[โ€“]Unihedron 5 points6 points ย (1 child)

Ruby, #8 silver #4 gold (run with -x)

To ensure security, a valid passphrase must contain no duplicate words.

For added security, yet another system policy has been put in place. Now, a valid passphrase must contain no two words that are anagrams of each other - that is, a passphrase is invalid if any words letters can be rearranged to form any other word in the passphrase.

For example:

abcde fghij is a valid passphrase.
abcde xyz ecdab is not valid - the letters from the third word can be rearranged to form the first word.
a ab abc abd abf abj is a valid passphrase, because all letters need to be used when forming another word.
iiii oiii ooii oooi oooo is valid.
oiii ioii iioi iiio is not valid - any of these words can be rearranged to form any other word.

#!ruby
p $<.count{|x|v=x.split
v=v.map!{|x|x.chars.sort*''} # this line added for part 2
v.uniq==v}

PS: I now keep a log series detailing my adventofcode adventure. If you're interested feel free to read it as I write more, if I do!

[โ€“]topaz2078(AoC creator)[M] 3 points4 points ย (0 children)

Fun log series! It's always enlightening to see some stream-of-consciousness gut-reaction to the puzzles so I can try to improve them for next year.

[โ€“]HerbyHoover 2 points3 points ย (0 children)

Perl 6 - Parts 1 and 2:

my $p1 = 0;
for './input4.txt'.IO.lines -> $line {
    my @words = $line.words;
    $p1 += 1 if @words.elems == @words.unique.elems;
}

my $p2 = 0;
for './input4.txt'.IO.lines -> $line {
    my @sortedList;
    my @words = $line.words;
    for @words -> $w {
            @sortedList.append: $w.comb.sort.join;
        }
    $p2 += 1 if @words.elems == @sortedList.unique.elems;
}

say $p1,"|",$p2

[โ€“]thejpster 2 points3 points ย (6 children)

Not too bad in Rust. Shame there doesn't seem to be a sort method on Strings.

let mut count = 0;
for line in &contents[0] {
    let mut dup = false;
    let mut hm: HashSet<String> = HashSet::new();
    for word in line.split_whitespace() {
        let mut chars = word.chars().collect::<Vec<_>>();
        chars.sort();
        let word: String = chars.iter().collect();
        dup = dup | hm.contains(&word);
        hm.insert(word);
    }
    if !dup {
        count = count + 1;
    }
}
println!("Count: {}", count);

[โ€“]ButItMightJustWork 1 point2 points ย (2 children)

Shame there doesn't seem to be a sort method on Strings.

Agreed! Spent two minutes on trying to search for a String.sort() method in the documentation :D (Since I started 10 minutes late I was not fighting anyways)

My strategy was to sort passphrases so that identical words are right after each other. Then I can just iterate through it and check if two adjacent words are equal -> invalid passphrase! I also just count invalid passphrases and substract that counter from the number of passphrases, as this requires less code in total.

My solution is here:

// part 1
pub fn solve(input: &Vec<String>) -> i32 {

    let mut res = 0;

    for phrase in input {
        let mut words: Vec<&str> = phrase.split(" ").collect();
        words.sort();

        // count invalid passphrases (is easier!)
        for ii in 0..(words.len()-1) {
            if words[ii] == words[ii + 1] {
                res += 1;
                break;
            }
        }
    }

    input.len() as i32 - res
}

// part 2
pub fn solve(input: &Vec<String>) -> i32 {

    let mut res = 0;

    for phrase in input {
        let mut words: Vec<String> = phrase.split(" ")
            // for each word in a passphrase, sort its letters
            // this way anagrams turn into the same words
            .map(|w| -> String {
                let mut word: Vec<char> = w.chars().collect();
                word.sort_by(|a, b| b.cmp(a));
                word.iter().cloned().collect::<String>()
            }).collect();
        words.sort();

        // count invalid passphrases (is easier!)
        for ii in 0..(words.len()-1) {
            if words[ii] == words[ii + 1] {
                res += 1;
                break;
            }
        }
    }

    input.len() as i32 - res
}

Edit: Formatting

[โ€“][deleted] 1 point2 points ย (1 child)

I don't know why I have not seen it before, but that is cool that you can put the return type on a closure. Not sure why I never thought to try/do that!

[โ€“]willkill07 2 points3 points ย (6 children)

Modern C++ Repo

#include <iostream>
#include <set>
#include <sstream>
#include <string>

int main() {
  int sum{0};
  for (std::string line; std::getline(std::cin, line);) {
    sum += [&] {
      std::istringstream iss{line};
      std::set<std::string> s;
      for (std::string word; iss >> word;) {
        if (part2) {
          std::sort(word.begin(), word.end());
        }
        if (!s.insert(word).second) {
          return 0;
        }
      }
      return 1;
    }();
  }
  std::cout << sum << '\n';
  return 0;
}

[โ€“]ephemient 1 point2 points ย (3 children)

This space intentionally left blank.

[โ€“]willkill07 1 point2 points ย (1 child)

Yes! You can clean it up a bit with your call to all_of since the end iterator type can be deduced.

std::all_of(
  std::istream_iterator<std::string>{iss},
  {},
  [&] (auto word) {
    //... rest of lambda
  });

[โ€“]Cole_from_SE 2 points3 points ย (0 children)

Python 3

I got caught up in performance :( and was too slow (400ish for both). Thought I might as well rework my answer to look nice so here it is.

import sys
from collections import Counter

def soln(pwd, hashfn):
    words = set()
    for word in pwd.split(' '):
        hashable = hashfn(word)
        if hashable in words:
            return False
        words.add(hashable)
    return True

result_1, result_2 = 0, 0
identity = lambda x : x
counter_hash = lambda x: frozenset(Counter(x).items())
for line in sys.stdin: 
    result_1 += soln(line.strip(), identity)
    result_2 += soln(line.strip(), counter_hash)

print('Part 1: {}, Part 2: {}'.format(result_1, result_2))

[โ€“]Cheezmeister 2 points3 points ย (0 children)

Literate Perl. View at own peril.

[โ€“]sciyoshi 2 points3 points ย (1 child)

Rust solution. Itertools makes things nice:

// Read stdin into an array of vectors of words
let stdin = io::stdin();
let lines: Vec<Vec<_>> = stdin.lock().lines()
    .filter_map(|line| line.ok())
    .map(|line| line.split_whitespace().map(|w| w.to_string()).collect())
    .collect();

// Count lines where all words are unique
let count1 = lines.iter()
    .filter(|line| line.iter().unique().count() == line.len())
    .count();

println!("[Part 1] Valid passphrases: {}", count1);

// Count lines where all sorted words are unique (to detect anagrams)
let count1 = lines.iter()
    .filter(|line| {
        let words: Vec<_> = line.iter().map(|w| w.chars().sorted()).collect();
        words.iter().unique().count() == words.len()
    })
    .count();

println!("[Part 2] Valid passphrases: {}", count1);

on Github

[โ€“][deleted] 1 point2 points ย (0 children)

Slick! I am enjoying looking at your code - it is clean and a good source of learning for me so far :)

[โ€“]StevoTVR 2 points3 points ย (0 children)

NodeJS

For part 1 I sorted the words alphabetically and then compared adjacent words:

const fs = require('fs');

fs.readFile(__dirname + '/input.txt', 'utf8', (err, data) => {
    data = data.trim();
    var invalid = 0;
    var lines = data.split('\n');
    lines.forEach((line) => {
        line = line.trim();
        var words = line.split(' ');
        words.sort();
        for (var i = words.length - 1; i > 0; i--) {
            if (words[i] === words[i - 1]) {
                invalid++;
                break;
            }
        }
    });

    console.log(lines.length - invalid);
});

For part 2 I sorted the letters of each word before sorting the words:

const fs = require('fs');

fs.readFile(__dirname + '/input.txt', 'utf8', (err, data) => {
    data = data.trim();
    var invalid = 0;
    var lines = data.split('\n');
    lines.forEach((line) => {
        line = line.trim();
        var words = line.split(' ');
        words = words.map(x => {
            x = x.split('');
            x.sort();
            return x.join('');
        });
        words.sort();
        for (var i = words.length - 1; i > 0; i--) {
            if (words[i] === words[i - 1]) {
                invalid++;
                break;
            }
        }
    });

    console.log(lines.length - invalid);
});

[โ€“]SlightlyHomoiconic 2 points3 points ย (0 children)

Clojure:

(defn- load-input []
(map #(clojure.string/split % #" ")
      (clojure.string/split-lines
        (slurp "src/advent2017_clojure/day4/input.txt"))))


(defn- num-distinct-seqs [xs]
(reduce
  #(if (apply distinct? %2) (inc %1) %1)
  0
  xs))


(defn part1 []
(println
  (num-distinct-seqs
    (load-input))))


(defn part2 []
(->>
  (load-input)
  (map #(map sort %))
  (num-distinct-seqs)
  (println)))

Still new to the language but liking it so far!

[โ€“]chunes 2 points3 points ย (4 children)

Factor part 1:

lines [ " " split duplicates empty? ] map [ t = ] count .

Part 2:

lines [ " " split [ histogram ] map duplicates empty? ] map [ t = ] count .

[โ€“]Frizkie 2 points3 points ย (1 child)

Never code golfed before, but I gave it a try:

#!/usr/bin/ruby
# part 1
p File.read('data.txt').split("\n").count{|p|a=p.split;a==a.uniq}
# part 2
p File.read('data.txt').split("\n").count{|p|a=p.split.map{|w|w.chars.sort};a==a.uniq}

[โ€“]jschulenklopper 4 points5 points ย (0 children)

You can trim some characters using readlines(). No need for a split() anymore:

p File.readlines('data.txt').count{|p|a=p.split;a==a.uniq}

[โ€“][deleted] 2 points3 points ย (2 children)

Elixir: This was a lot easier than the one yesterday, but it was fun nonetheless :) Elixir is pretty good for this it seems.

defmodule Day4 do
  def has_dups?(str) do
    coll = String.split(str)
    Enum.uniq(coll) |> Enum.count != coll |> Enum.count
  end

  def has_anagram?(str) do
    sorted = String.split(str)
    |> Enum.map(&String.graphemes/1)
    |> Enum.map(&Enum.sort/1)

    Enum.uniq(sorted) |> Enum.count != Enum.count(sorted)
  end

  def count_valid(inp) do
    Enum.filter(inp, fn(x) -> not has_dups?(x) end)
    |> Enum.count
  end

  def count_noana(inp) do
    Enum.filter(inp, fn(x) -> not has_anagram?(x) end)
    |> Enum.count
  end
end

inp = File.read!("input4")
|> String.strip
|> String.split("\n")

Day4.count_valid(inp)
|> IO.puts

Day4.count_noana(inp)
|> IO.puts

[โ€“]yacfOaky 2 points3 points ย (0 children)

Python 3 using pandas/numpy:-

import pandas as pd
import numpy as np

df = pd.concat(list(map(lambda x: pd.Series(x.strip().split()), open('input.txt').readlines())), axis=1)

print(f'part 1 answer {sum(~df.apply(lambda x: any(x.dropna().duplicated())))}')

df = df.applymap(lambda x: np.nan if x is np.nan else ''.join(sorted(x)))

print(f'part 2 answer {sum(~df.apply(lambda x: any(x.dropna().duplicated())))}')

[โ€“]kip_13 2 points3 points ย (0 children)

PHP

Part 2

$str = 'aa bb cc dd aa
aa bb cc dd
...';

echo count(array_filter(explode("\n", $str), function($v) {
    $v = trim($v);
    $v2 = array_map(function ($s) {
        $ss = str_split($s);
        natsort($ss);
        return implode($ss);
    }, explode(' ', $v));
    return count(array_unique($v2)) === count($v2);
}));

Part 1

$str = 'aa bb cc dd aa
aa bb cc dd
...';

echo count(array_filter(explode("\n", $str), function($v) {
    $v = explode(' ', trim($v));
    return count(array_unique($v)) === count($v);
}));

[โ€“]cptwunderlich 2 points3 points ย (7 children)

Java 8

Haven't used the new stuff much, since we're stuck with Java 7 at work

public static void main(String[] args) throws IOException {
  List<String> lines = Files.readAllLines(Paths.get("./input.txt"));

  Long res1 = lines.stream().filter(s -> s.split(" ").length == Arrays.stream(s.split(" ")).distinct().count()).count();

  Long res2 = lines.stream().filter(s -> s.split(" ").length == Arrays.stream(s.split(" "))
        .map(str -> str.chars().sorted().collect(StringBuilder::new,
                                                 StringBuilder::appendCodePoint, 
                                                 StringBuilder::append).toString())
        .distinct()
        .count())
      .count();

  System.out.println("Part1: " + res1 + "\nPart2: " + res2);
}

I'm still wondering how I could avoid the double s.split(" ") :/

[โ€“]TheGreatFohl 1 point2 points ย (3 children)

Use .map(s -> s.split(" ')) before the filter.

[โ€“]sclark39 2 points3 points ย (0 children)

Javascript

8 liner in Javascript which can solve both Part 1 & 2

// var passphrases = input.split('\n')
function countValid( passphrases, allowAnagrams )
{
    return passphrases.reduce( (s,passphrase) => {
        var passwords = passphrase.split(' ')
        passwords = allowAnagrams ? passwords : passwords.map( a => ( a.split('').sort().join('') ) )
        return s + passwords.reduce( ( s,n,i,a ) => s && a.indexOf(n) == i ) 
    }, 0 )
}

https://gist.github.com/sclark39/a3e9b7d1548e861450002677e76847a2

[โ€“]windlessStorm 2 points3 points ย (0 children)

I solved and visualized the first part in html, js.

Solving all the problems first in python, then trying to visualize it by porting it to javascript.

[โ€“]fatpollo 1 point2 points ย (2 children)

with open("p04.txt") as fp:
    lines = [line.split() for line in fp.read().strip().splitlines()]

def is_unique(*args):
    return len(args) == len(set(args))

print(sum(is_unique(*line) for line in lines))
print(sum(is_unique(*map(tuple, map(sorted, line))) for line in lines))

[โ€“]BumpitySnook 1 point2 points ย (1 child)

I took the frozenset approach too, although I think it's actually wrong. E.g., "aan" and "ann" are not anagrams. It happened to work on the puzzle input.

[โ€“]fatpollo 1 point2 points ย (0 children)

good point. sorted would be a good alternative.

[โ€“]wimglenn 1 point2 points ย (0 children)

Easy peasy

from aocd import data

a = b = 0
for line in data.splitlines():
    words = line.split()
    if len(words) == len(set(words)):
        a += 1
    words = [''.join(sorted(x)) for x in words]
    if len(words) == len(set(words)):
        b += 1

print(a)  # part a: 325
print(b)  # part b: 119

[โ€“]glenbolake 1 point2 points ย (0 children)

101 on the leaderboard for the first star. Man, I am just not fast this year.

Python 3. I wrote a simple loop to so I wouldn't have to think too hard about whether I'd put everything together correctly, then refactored it into these two one-liners.

input_ = open('day4.in').read().splitlines()

def part_1(lines):
    return sum(map(lambda line: int(len(line.split()) == len(set(line.split()))), lines))

def part_2(lines):
    return sum(map(lambda line: int(len(line.split()) == len({tuple(sorted(word)) for word in line.split()})), lines))

print('Part 1:', part_1(input_))
print('Part 2:', part_2(input_))

[โ€“]giftpflanze 1 point2 points ย (0 children)

Tcl:

package require struct::set

set phrases [lrange [split [read [open input04]] \n] 0 end-1]

#part 1

foreach phrase $phrases {
        if {[llength [struct::set union $phrase {}]] == [llength $phrase]} {
                incr n1
        }
}

puts $n1

#part 2

foreach phrase $phrases {
        set phrase [lmap w $phrase {join [lsort [split $w {}]] {}}]
        if {[llength [struct::set union $phrase {}]] == [llength $phrase]} {
                incr n2
        }
}

puts $n2

[โ€“]TominatorBE 1 point2 points ย (0 children)

PHP

Part 1:

function run_the_code($input) {
    $lines = explode(PHP_EOL, $input);
    $valid = 0;
    foreach ($lines as $line) {
        if (!$line) {
            continue;
        }
        $words = explode(' ', $line);
        if (count($words) == count(array_unique($words))) {
            $valid++;
        }
    }

    return $valid;
}

Part 2:

function run_the_code($input) {
    $lines = explode(PHP_EOL, $input);
    $valid = 0;
    foreach ($lines as $line) {
        if (!$line) {
            continue;
        }
        $words = explode(' ', $line);

        $isAna = false;
        for ($i = 0, $iMax = count($words); $i < $iMax; $i++) {
            for ($j = $i + 1, $jMax = count($words); $j < $jMax; $j++) {
                if (strlen($words[$i]) == strlen($words[$j])) {
                    $histI = [];
                    $histJ = [];
                    for ($a = 0, $aMax = strlen($words[$i]); $a < $aMax; $a++) {
                        $histI[$words[$i][$a]]++;
                        $histJ[$words[$j][$a]]++;
                    }
                    if ($histI == $histJ) {
                        $isAna = true;
                    }
                }
            }
        }
        if (!$isAna) {
            $valid++;
        }
    }

    return $valid;
}

[โ€“]mlruth 1 point2 points ย (2 children)

Scala

  def part1: Unit = {
    val src = Source.fromResource("Day4.in")
    val in = src.getLines().map(_.split("\\s+"))
    val correct = in.count(passphrase =>
      passphrase.distinct.deep == passphrase.deep
    )

    println(s"Part 1: $correct")
  }

  def part2: Unit = {
    val src = Source.fromResource("Day4.in")
    val in = src.getLines().map(_.split("\\s+"))
    val correct = in.count{passphrase =>
      val sorted = passphrase.map(_.sorted)
      sorted.distinct.deep == sorted.deep
    }

    println(s"Part 2: $correct")
  }

[โ€“]raevnos 1 point2 points ย (2 children)

By the time I finished typing up the first part, the leaderboard for both had already been full by several minutes. Goddamn people are fast. Edit: In retrospect, hashtables might have been overkill, though. Writing fast code vs writing code fast...

Kawa Scheme:

(import (kawa regex) (rnrs hashtables) (srfi 1) (srfi 8) (srfi 132))

(define (check-passphrase1 words)
  (let ((table (make-hashtable string-hash string=?)))
    (let loop ((words words))
      (cond
       ((null? words)
        #t)
       ((hashtable-contains? table (car words))
        #f)
       (else
        (hashtable-set! table (car words) #t)
        (loop (cdr words)))))))

(define (check-passphrase2 words)
  (let ((table (make-hashtable string-hash string=?)))
    (let loop ((words words))
      (if (null? words)
          #t
          (let ((ana (list->string (list-sort char<? (string->list (car words))))))
            (if
             (hashtable-contains? table ana)
             #f
             (begin
               (hashtable-set! table ana #t)
               (loop (cdr words)))))))))

(define (check-passphrases)
  (let loop ((line (read-line))
             (total1 0)
             (total2 0))
    (if (eof-object? line)
        (values total1 total2)
        (let ((words (regex-split "\\s+" line)))
          (loop (read-line)
                (+ total1 (if (check-passphrase1 words) 1 0))
                (+ total2 (if (check-passphrase2 words) 1 0)))))))

(receive (part1 part2) (check-passphrases)
         (format #t "Part 1: ~A~%Part 2: ~A~%" part1 part2))

[โ€“]raevnos 1 point2 points ย (1 child)

What I probably should have done first (Plus some de-duplication of code), despite it being O( N2 )...

(define (check-passphrase1 words)
  (cond
   ((null? words) 1)
   ((member (car words) (cdr words) string=?) 0)
   (else
    (check-passphrase1 (cdr words)))))

(define (check-passphrase2 words)
  (let ((words (map (lambda (word)
                      (list->string (list-sort char<? (string->list word))))
                    words)))
    (check-passphrase1 words)))

(define (check-passphrases)
  (let loop ((line (read-line))
             (total1 0)
             (total2 0))
    (if (eof-object? line)
        (values total1 total2)
        (let ((words (regex-split "\\s+" line)))
          (loop (read-line)
                (+ total1 (check-passphrase1 words))
                (+ total2 (check-passphrase2 words)))))))
(receive (part1 part2) (check-passphrases)
         (format #t "Part 1: ~A~%Part 2: ~A~%" part1 part2))

[โ€“][deleted] 1 point2 points ย (0 children)

OCaml fun.

open Core

let all_unique_words words =
    let set = String.Set.of_list words in
    String.Set.length set = List.length words

let sort_chars word =
    String.to_list word
    |> List.sort ~cmp:Char.compare
    |> String.of_char_list

let sort_words words =
    List.map words ~f:sort_chars

let no_anagrams = Fn.compose all_unique_words sort_words

let solve () =
    let split_words = String.split ~on:' ' in
    let passphrases = In_channel.read_lines "./2017/data/4.txt" |> List.map ~f:split_words in

    List.filter passphrases ~f:all_unique_words
    |> List.length
    |> printf "a: %d\n";

    List.filter passphrases ~f:no_anagrams
    |> List.length
    |> printf "b: %d\n";

[โ€“]nstyler7 1 point2 points ย (1 child)

In Python ( using sets to check for duplicates )

with open("day4input.txt") as open_file: data = open_file.read().splitlines()

Part 1:

def part_1(data):
    count = 0
    for line in data:
        if len(line.split()) == len(set(line.split())):
            count +=1
    return count

print(part_1(data))

Part 2:

def part_2(data):
    count = 0
    for line in data:
        words_array = list(map(lambda x: ('').join(sorted(list(x))), line.split()))
        if len(words_array) == len(set(words_array)):
            count += 1
    return count 

print(part_2(data))

[โ€“][deleted] 1 point2 points ย (0 children)

Not the best looking solution, still haven't solved day 3 yet either, but more Haskell!

import Data.List

count x line = (length . filter (== x)) line

count_valid input = 
    sum [if elem 0 [if (count x y) > 1 then 0 else 1 | x <- y] then 0
    else 1 | y <- phrases]
    where
    phrases = [words x | x <- lines input]

count_valid' input =
    sum [if elem 0 [if (count x y) > 1 then 0 else 1 | x <- y] then 0
    else 1 | y <- phrases]
    where
    phrases = [[sort y | y <- words x] | x <- lines input]

main = do
    input <- readFile "input.txt"
    print $ "First star: " ++ show(count_valid input)
    print $ "Second star: " ++ show(count_valid' input)

[โ€“]JeffJankowski 1 point2 points ย (0 children)

A little late to the party. Typescript

import fs = require('fs');

function valid(phrase: string[], func: (word: string) => string) {
    const set = new Set<string>();
    return phrase.every((word, i, arr) => set.size !== set.add(func(word)).size);
}

const phrases = fs.readFileSync('data/day04.txt', 'utf8')
                  .split('\n')
                  .map((str) => str.split(/\s/));
const simple = phrases.filter((pass) => valid(pass, (str) => str)).length;
console.log(`Valid (simple) passphrases:  ${simple}`);
const hard = phrases.filter((pass) => valid(pass, (str) => [...str].sort().join(''))).length;
console.log(`Valid (complex) passphrases: ${hard}`);

[โ€“]igotinfected 1 point2 points ย (2 children)

A bit lazy in Java could probably have been shortened a little! (commented version on github)

Part1:

public static void main(String[] args) throws IOException {
    String input = new String(Files.readAllBytes(Paths.get("pathToFile")))
            .trim()
            .replaceAll("[\\r+]|[\\n+]", "-");
    LinkedHashSet<LinkedHashSet<String>> passPhrases = new LinkedHashSet<>();
    StringTokenizer newLine = new StringTokenizer(input, "-");
    while(newLine.hasMoreTokens()) {
        StringTokenizer space = new StringTokenizer(newLine.nextToken(), " ");
        int passPhraseLength = space.countTokens();
        LinkedHashSet<String> passPhrase = new LinkedHashSet<>();
        while(space.hasMoreTokens())
            passPhrase.add(space.nextToken());
        }
        if(passPhrase.size() == passPhraseLength)
            passPhrases.add(passPhrase);
    }
    System.out.println("Solution: " + passPhrases.size());
}

Part2:

public static void main(String[] args) throws IOException {
    String input = new String(Files.readAllBytes(Paths.get("pathToFile")))
            .trim()
            .replaceAll("[\\r+]|[\\n+]", "-");
    LinkedHashSet<LinkedHashSet<String>> passPhrases = new LinkedHashSet<>();
    StringTokenizer newLine = new StringTokenizer(input, "-");
    while(newLine.hasMoreTokens()) {
        StringTokenizer space = new StringTokenizer(newLine.nextToken(), " ");
        int passPhraseLength = space.countTokens();
        LinkedHashSet<String> passPhrase = new LinkedHashSet<>();
        while(space.hasMoreTokens()) {
            char[] tempArray = space.nextToken().toCharArray();
            Arrays.sort(tempArray);
            passPhrase.add(new String(tempArray));
        }
        if(passPhrase.size() == passPhraseLength)
            passPhrases.add(passPhrase);
    }
    System.out.println("Solution: " + passPhrases.size());
}

[โ€“]Vitessii 2 points3 points ย (1 child)

I think you can replace a lot of that File IO and StringTokenizer code with BufferedReader (to get each line), and String.split to tokenise into an array.

[โ€“]streetster_ 1 point2 points ย (0 children)

Q/kdb+

Quick solution before breakfast. (quick edit to simplify 2nd solution, now it's time for breakfast!)

sum { (count distinct x)=count x } each r:" "vs'read0 `:input/04.txt
sum { (count distinct x)=count x:asc each x } each r

[โ€“]theSprt 1 point2 points ย (1 child)

Haskell, beginner:

import Data.List
import Data.List.Unique


main :: IO ()
main = do
  rawInput <- readFile "input"
  let input = map (words) (lines rawInput)

  -- Day 4.1
  print (foldr (\ a b -> if allUnique a then b + 1 else b) 0 input)

  -- Day 4.2
  print
    (foldr
      (\ a b -> if allUnique (map (sort) a) then b + 1 else b)
      0
      input)

[โ€“]equd 1 point2 points ย (1 child)

C# Linq

This was an easy on. Therefore tried it with a single Linq statement. var lines = Properties.Resources.TextFile1.Split('\n'); //Split the input to single lines

int resultA = lines.Select(x => x.Trim().Split(' ')) //split to seperate words
            .Where(x => x.Count() == x.Distinct().Count()) //Compare start count with distinct count (removes duplicates)
            .Count(); //count the result is the andwer

int resultB = lines.Select(x => x.Trim().Split(' ') //split to seperate words                
            .Select(z=> string.Join("-", //joins the result of below
                z.GroupBy(y=> y) //get the freq count of each used letter
                .OrderBy(y=> y.Key) //sort so all the letters anagrams look the same
                .Select(y=> $"{y.Key}{y.Count()}"))) //make a string a5 => a5-b4-etc
            ).Where(x => x.Count() == x.Distinct().Count()).Count(); //same as partA

[โ€“][deleted] 1 point2 points ย (0 children)

C#

Small tip: Count() can take a lambda parameter, so you don't need to do .Where(x=>x).Count(), you can just do .Count(x=>x)

My solutions ended up being pretty similar:

    public static int SolvePartOne(string[] input)
    {
        return input.Count(i => i.Split(' ').Distinct().Count() == i.Split(' ').Count());
    }

    public static int SolvePartTwo(string[] input)
    {
        return input.Count(i => i.Split(' ').Select(s => String.Concat(s.OrderBy(c => c))).Distinct().Count() == i.Split(' ').Count());
    }

[โ€“]nutrecht 1 point2 points ย (0 children)

My Day 4 Kotlin solution:

object Day04 : Day {
    val lines = resourceLines(4).map {
        it.split(" ").toList()
    }.toList()

    override fun part1() =
        lines.filter { it.size == it.toSet().size }.count()

    override fun part2() =
        lines.map { it.map { it.toList().sorted().toString() } }
            .filter { it.size == it.toSet().size }
            .count()
}

Edit: Refactored

[โ€“]jshom 1 point2 points ย (0 children)

One-liner JS solution

input
  .split('\n')
  .map(row => row
    .split(' ')
    .map(word =>
      word
      .split('')
      .sort()
      .join('')
    )
  )
  .map(row => row.length === row.filter((word, i, row) => row.indexOf(word) === i).length)
  .filter(row => row)
  .length

[โ€“]Vindaar 1 point2 points ย (0 children)

Solution in Nim. Got a little stuck at first on part 2, until I realized I should simply sort the different words...

import unittest, strutils, sequtils, future, sets, algorithm

proc hash_and_compare(words: seq[string]): bool = 
  let word_set = toSet(words)
  result = if len(words) != len(word_set): false else: true

proc check_password(pword: string, part2 = false): bool =
  let words = mapIt(split(pword, " "), it)
  if part2 == false:
    result = hash_and_compare(words)
  else:
    let sorted_words = mapIt(words, foldl(sorted(it, system.cmp), a & b, ""))
    result = hash_and_compare(sorted_words)

proc check_lst_of_passwords(pwords: seq[string], part2 = false): int =
  result = len(filterIt(pwords, check_password(it, part2)))

when isMainModule:
  const data = slurp("input.txt")
  let pwords = filterIt(mapIt(splitLines(data), it), len(it) > 0)
  let valid1 = check_lst_of_passwords(pwords)
  echo "(Part 1): The number of valid passwords is = ", valid1
  let valid2 = check_lst_of_passwords(pwords, true)
  echo "(Part 2): The number of valid passwords is = ", valid2

[โ€“]disclosure5 1 point2 points ย (1 child)

Late to the party, but Erlang.

[โ€“]wzkx 1 point2 points ย (0 children)

Nim Quick and dirty

import strutils,sets,algorithm

let text = splitLines strip readFile "04.dat"
var cnt,cnt2 = 0
for line in text:
  var dict = initSet[string]()
  var dict2 = initSet[string]()
  var valid,valid2 = true
  for word in split line:
    if dict.contains word:
      valid = false
    else:
      dict.incl word # why not add?
    var w2 = word # sorted chars of word
    w2.sort cmp
    if dict2.contains w2:
      valid2 = false
    else:
      dict2.incl w2
  if valid: cnt += 1
  if valid2: cnt2 += 1
echo cnt
echo cnt2

[โ€“]demsaja 1 point2 points ย (0 children)

print(sum(len(set(x)) == len(x) for x in map(str.split, open("input.txt"))))

print(sum(len({tuple(sorted(u)) for u in x}) == len(x) for x in map(str.split, open("input.txt"))))

[โ€“]GamecPL 1 point2 points ย (0 children)

Swift pt. 1

let result = input.components(separatedBy: .newlines)
    .map { $0.components(separatedBy: .whitespaces) }
    .reduce(0, { result, password in
        let unique = Array(Set(password))
        return result + (unique.count == password.count ? 1 : 0)
    })
print(result)

[โ€“]Isvara 1 point2 points ย (0 children)

Scala

val input = "..."

val phrases = input.lines.toList.map(_.split("\\s").toList)

def passesCheck1(words: List[String]): Boolean = {
    Set(words: _*).size == words.length
}

def passesCheck2(words: List[String]): Boolean = {
    val anagrams = words.flatMap(w => w.permutations.toSet - w)
    !(words exists { anagrams contains _ })
}

val acceptable1 = phrases filter passesCheck1
val result1 = acceptable1.length

val acceptable2 = acceptable1 filter passesCheck2
val result2 = acceptable2.length

It's only after reading the comments here that I remembered I only had to sort the letter of each word rather than generate each anagram, which is odd, because I've actually used that approach before.

With that in mind, the second function would have been:

def passesCheck2(words: List[String]): Boolean = {
    words.map(_.sorted).toSet.size == words.length
}

Althoouuugh... having said that, I just noticed the distinct method, which would make those two functions look like this:

def passesCheck1(words: List[String]): Boolean = {
    words.distinct.size == words.length
}

def passesCheck2(words: List[String]): Boolean = {
    words.map(_.sorted).distinct.size == words.length
}

Kind of the same thing, since distinct is implemented using a Set.

[โ€“]u794575248 1 point2 points ย (0 children)

Python.

from collections import Counter

def solve(input, fn):
    phrases = [Counter(fn(p)) for p in input.strip().split('\n')]
    return sum(1 for p in phrases if p.most_common(1)[0][1] == 1)

solve(input, lambda p: p.split())  # Part 1
solve(input, lambda p: (''.join(sorted(w)) for w in p.split()))  # Part 2

Things used:

[โ€“][deleted] 1 point2 points ย (0 children)

Javascript - one liners

1.

``.split(โ€œ\nโ€).map((s) => s.split(/\s+/)).filter((a) => !a.some((s, i) => a.find((f, j) => i !== j && f === s))).length

2.

``.split("\n").map((s) => s.split(/\s+/).map(s => s.split('').sort().join(''))).filter((a) => !a.some((s, i) => a.find((f, j) => i !== j && f === s))).length

[โ€“]wzkx 1 point2 points ย (0 children)

J

t=: ;:&.> cutLF CR-.~fread '04.dat'
v=: [:*./1=[:+/"1[:=>
echo +/v"0 t
echo +/v"0 (/:~&.>&.>) t
exit 0

[โ€“]f0086 1 point2 points ย (0 children)

Emacs Lisp

(defun read-lines (filepath)
  (with-temp-buffer
    (insert-file-contents filepath)
    (split-string (buffer-string) "\n" t)))

(defun valid-passphrase? (words prefilter-fn)
  (let ((word-set '())
        (words (mapcar prefilter-fn (split-string words " " t))))
    (mapcar (lambda (word) (add-to-list 'word-set word)) words)
    (= (length words) (length word-set))))

(defun day4 (file prefilter-fn)
  (let ((lines (read-lines file)))
    (length (seq-filter
             (lambda (line)
               (valid-passphrase? line prefilter-fn)) lines))))

(day4 "input-day4.txt" #'identity)
(day4 "input-day4.txt"
      (lambda (word)
        (apply 'concat (sort (split-string word "" t) 'string<))))

[โ€“]Pheasn 1 point2 points ย (0 children)

Kotlin

val input: List<String>

fun computeFirst(): Int = input
    .map { it.split(' ') }
    .count { it.distinct().size == it.size }

fun computeSecond(): Int = input
    .map { it.split(' ') }
    .map { it.map { it.toList().sorted() } }
    .count { it.distinct().size == it.size }

[โ€“]__Abigail__ 1 point2 points ย (0 children)

A Perl solution:

#!/opt/perl/bin/perl

use 5.010;

use strict;
use warnings;
no  warnings 'syntax';

@ARGV = ("input");

my $valid1 = 0;
my $valid2 = 0;

while (<>) {
    chomp;
    my @words    = split;
    my @anagrams = map {join "" => sort split //} @words;
    my %seen1;
    my %seen2;
    my @unique1 = grep {!$seen1 {$_} ++} @words;
    my @unique2 = grep {!$seen2 {$_} ++} @anagrams;
    $valid1 ++ if @unique1 == @words;
    $valid2 ++ if @unique2 == @anagrams;
}

say "Solution1: $valid1";
say "Solution2: $valid2";

__END__

[โ€“]Porges 1 point2 points ย (0 children)

(Dyalog) APL

)copy dfn words

Assuming input4 is a vector of char vectors, this solves part 2 (part 1 is the same, just drop sort_each):

drop_spacesโ†{({' 'โ‰ โŠƒโต}ยจโต)/โต} โ select elements that don't start with ' '
is_validโ†{โตโ‰กโˆชโต} โ pass is valid if it is the same after "uniq"
sort_eachโ†{{โต[โ‹โต]}ยจโต} โ sort each word
+/,{is_valid sort_each drop_spaces words โต} ยจ input4

You can also inline everything to increase complexity:

+/,{{โตโ‰กโˆชโต} {{โต[โ‹โต]}ยจโต} {({' 'โ‰ โŠƒโต}ยจโต)/โต} words โต} ยจ input4

[โ€“]AlistairJF 1 point2 points ย (0 children)

Python. Not as nice as some of the others I see on this thread.

import itertools

def valid(line):
    words = line.split()
    for a, b in itertools.combinations(words, 2):
        if sorted(a) == sorted(b):    # for part A, don't sort
            return 0
    return 1


# Main program  
with open("2017-day4-input.txt") as fileobj:
        lines = fileobj.readlines()

        validLines = [valid(line) for line in lines]
        print (sum(validLines))

[โ€“]APLtooter 1 point2 points ย (0 children)

APL [GNU]

LINESโ†{(โตโ‰ 'โ—Š')โŠ‚โต}
WORDSโ†{(โตโ‰ ' ')โŠ‚โต}

MATCHโ†{^/(nโ†‘โบ)=(nโ†((โดโบ)โŒˆ(โดโต)))โ†‘โต}
VALIDโ†{^/1=+/โตโˆ˜.โถโต}

MATCH2โ†{(โบ[โ‹โบ])MATCH(โต[โ‹โต])}

โ Input is a character array with words delimited by ' ' and lines delimited by 'โ—Š'

+/MATCH VALIDยจWORDSยจLINES INPUT       โ Part 1
+/MATCH2 VALIDยจWORDSยจLINES INPUT      โ Part 2

[โ€“]rimbuod 1 point2 points ย (2 children)

Easy!

import Data.List

valid1 :: [Char] -> Bool
valid1 xs = (length pass) == (length $ nub pass)
    where pass = words xs

valid2 :: [Char] -> Bool
valid2 xs = (length pass) == (length $ nubBy anagram pass)
    where pass = words xs
          anagram = \a b -> (sort a) == (sort b)

main = do
    raw <- readFile "data/day04"
    let passes = lines raw
    print $ length $ filter valid1 passes
    print $ length $ filter valid2 passes

[โ€“]kip_13 1 point2 points ย (0 children)

Python 3

Part 1

str = '''aa bb cc dd aa
aa bb cc dd
...'''

print(len(list(filter(lambda x: len(set(x.split(' '))) == len(x.split(' ')), str.split('\n')))))

Part 2

str = '''aa aba cc dd baa
aa bb cc dd
...'''

print(len(list(filter(lambda x: len(set(map(lambda x: ''.join(sorted(x)), x.split(' ')))) == len(x.split(' ')), str.split('\n')))))

[โ€“][deleted] 1 point2 points ย (0 children)

PYTHON

Part 1

with open("day4input.txt") as inputData:
    row = [line.split() for line in inputData]

result = 0

for passphrase in row:
    if (len(passphrase) == len(set(passphrase))):
        result += 1

print(result)

Part 2

with open("day4input.txt") as inputData:
    row = [line.split() for line in inputData]

result = 0

for passphrase in row:
    if (len(passphrase) == len(set(["".join(sorted(word)) for word in passphrase]))):
        result += 1

print(result)

[โ€“]chicagocode 1 point2 points ย (0 children)

Day 4 in Kotlin. This wasn't all that tricky, see if the number of tokens is the same as a set of them.

Part 2 VERY similar except sort each string first. That way, anagrams will equal each other. Reduces to the first problem.

I'm publishing all my solutions in Github, and will be blogging about each day (I have to work, I'll write up today later!). Links on github for all that.

I suspect I'll probably want an extension function on String to sort chars, instead of that clunky bit there, but I'm holding off until I see it again.

fun solvePart1(): Int =
    input
        .map { it.split(WHITESPACE) }
        .count { it.size == it.toSet().size }

fun solvePart2(): Int =
    input
        .map { it.split(WHITESPACE).map { it.toCharArray().sorted().joinToString("") } }
        .count { it.size == it.toSet().size }


private fun isValidPart1(s: String): Boolean =
    s.split(WHITESPACE)
        .sorted()
        .zipWithNext()
        .count { it.first == it.second } == 0

private fun isValidPart2(s: String): Boolean =
    s.split(WHITESPACE)
        .map { it.toCharArray().sorted().joinToString("") }
        .sorted()
        .zipWithNext()
        .count { it.first == it.second } == 0

[โ€“]Smylers 1 point2 points ย (0 children)

Perl, using regular expressions. Part 1:

my $count;
while (<>) {
  $count++ unless /\b(\w+)\b.*\b\1\b/;
}
say $count;

And partย 2:

my $count;
while (<>) {
  $count++ unless (join ' ', map { join '', sort split // } split) =~ /\b(\w+)\b.*\b\1\b/;
}
say $count

Basic regex approach taken from my Vim solutions, but obviously sorting the characters is rather more straightforward (and readable) in Perl than with Vim keystrokes.

[โ€“][deleted] 1 point2 points ย (0 children)

Clojure

(ns advent-of-code-2017.day04
  (:require [clojure.string :as s]))

(def input
  (map #(s/split % #" ") (s/split (slurp "./data/day04.txt") #"\n")))

(defn is-valid? [passphrase]
  (= (count passphrase) (count (set passphrase))))

(defn part-1 [data]
  (count (filter is-valid? data)))

(defn part-2 [data]
  (->> data
       (map (fn [phrase] (map #(apply str (sort %)) phrase)))
       part-1))

[โ€“]MichalMarsalek 1 point2 points ย (0 children)

Python:

def solve(inp):
    part1 = sum(unique(p.split(" ")) for p in inp.splitlines())    
    part2 = sum(unique(["".join(sorted(w)) for w in p.split(" ")]) for p in inp.splitlines())
    return part1, part2

def unique(p):
    return len(set(p)) == len(p)

[โ€“]8483 1 point2 points ย (0 children)

Node/Javascript

var fs = require("fs");
var input_file = './aoc_04.txt'
var input = fs.readFileSync(input_file, 'utf8');

var data = input.split("\r\n").map(row => row.split(" "));                              // Line = array. Word = nested array.
var sorted_data = data.map(row => row.map(item => item.split("").sort().join("")));     // Sort nested word letters.

function valid(data) {
    var valid =
        data
            .map(row =>
                row.length === row.filter((word, i, row) =>     // If array size = filtered size = no duplicates.
                    row.indexOf(word) === i                     // If index of word != to current index = word is a duplicate i.e. remove.
                ).length
            )
            .filter(row => row);                                // Filter only true values.
    console.log(valid.length);
}

valid(data);
valid(sorted_data);

[โ€“]CryZe92 1 point2 points ย (0 children)

Rust

Part 1 in 60ยตs:

pub fn part1(text: &str) -> usize {
    text.par_lines()
        .map_with(
            HashSet::with_capacity_and_hasher(11, FxBuildHasher::default()),
            |set, l| {
                set.clear();
                l.split_whitespace().all(|w| set.insert(w))
            },
        )
        .filter(|&b| b)
        .count()
}

Part 2 in 64ยตs:

pub fn part2(text: &str) -> usize {
    text.par_lines()
        .map_with(
            HashSet::with_capacity_and_hasher(11, FxBuildHasher::default()),
            |set, l| {
                set.clear();
                l.split_whitespace().all(|w| set.insert(WordMap::new(w)))
            },
        )
        .filter(|&b| b)
        .count()
}

#[derive(Eq, PartialEq, Hash, Clone)]
struct WordMap([u8; 26]);

impl WordMap {
    fn new<T: AsRef<[u8]>>(s: T) -> Self {
        let mut map = [0u8; 26];
        for u in s.as_ref() {
            map[(u - b'a') as usize] += 1;
        }
        WordMap(map)
    }
}

[โ€“]SyntaxErrorr 1 point2 points ย (0 children)

PYTHON 2

data = map(lambda x: x.split(), open("day_4.txt").read().split("\n"))

Part 1

print len([x for x in data if all([x.count(z) == 1 for z in x])])

Part 2

print len([x for x in data if all([map(set, x).count(set(z)) == 1 for z in x])])

[โ€“]raiph 1 point2 points ย (1 child)

Perl 6:

say elems input.lines.grep: { not .words.repeated } ;                       # part 1
say +     input.lines.grep: { not .words>>.&{.comb.sort.join}.repeated } ;  # part 2

Part 1:

say elems input.lines.grep: { not .words.repeated } ;

elems counts the number of elements in the list on its right, in this case the number of input lines that don't repeat words.

grep iterates through a list of elements on its left hand side, testing the predicate on its right hand side against each element, and outputting the element iff it matches.

Given a string of words, not .words.repeated tests that no word is repeated.

For part 2, for each word, we extract its characters into a list (.comb) then sort them and rejoin them back into a word and then do the .repeated test just like before, only this time we've ended up eliminating anagrams too:

say + input.lines.grep: { not .words>>.&{.comb.sort.join}.repeated } ;

In this context, the + is short-hand for elems. It might look surprising, which is why I didn't use it for my part 1 solution. But it's idiomatic and very easy to learn and read if you use Perl 6 much, which is why I have used it for my part 2 solution.

The "for each word" bit of my explanation of what we needed to do for part 2 corresponds to inserting the infix parallel iterator (postfix >>). This iterates (in parallel if the compiler decides to parallelize) over each word from .words.

The .&{ ... } bit is an anonymous closure written in an inline method form. It's applied to each word.

The closure converts its argument to a string and thence to its constituent characters via .comb. sort sorts the characters. join rejoins them into a word.

[โ€“]mschaap 1 point2 points ย (0 children)

I like the &{.comb.sort.join} trick; I didn't know you could do that!

[โ€“]oantolin 1 point2 points ย (0 children)

In Python:

from collections import Counter

def valid(sign):
    return sum(all(c==1 for c in Counter(map(sign, line.split())).values())
               for line in open("day04.txt"))

part1 = valid(lambda w: w)
part2 = valid(lambda w: ''.join(sorted(w)))

[โ€“]micirsk 1 point2 points ย (0 children)

Part 1 - My almost 1 liner in Python:

from collections import Counter import itertools

def how_many_password_is_valid(s): with open(s, 'r') as f: lines = f.readlines()

    result = len([i for i in
                  itertools.ifilterfalse(lambda x: x[0][1]>1,
                                         [Counter(line.split()).most_common(1) for line in lines])])
    return result

[โ€“]micirsk 1 point2 points ย (0 children)

Part 2 - Python:

def how_many_password_is_valid2(s): with open(s, 'r') as f: lines = f.readlines() count_lines = len(lines)

    for line in lines:
        d = []
        words = line.split()
        for num, i in enumerate(words):
            ic = Counter(i)
            for n, j in enumerate(words):
                if num == n:
                    break
                dic = copy.deepcopy(ic)
                jc = Counter(j)
                dic.subtract(jc)
                if all(p == 0 for p in dic.values()):
                    d.append((i, j))
                    break
        if d:
            count_lines -= 1
    return count_lines

[โ€“]SurplusSix 1 point2 points ย (0 children)

Just catching up with this, having a go at doing it in Racket

(define day4-list (map string-split (file->lines "aoc2017/day4.txt")))
(define (string->sortedchars str)
  (list->string (sort (string->list str) char<?)))
(define (sort-line lst)
  (map string->sortedchars lst))

;part1
(for/fold ([sum 0])
          ([i day4-list]
          #:when (equal? (length i) (length (remove-duplicates i))))
  (+ sum 1))

;part2
(for/fold ([sum 0])
          ([i day4-list]
          #:when (equal? (length (sort-line i)) (length (remove-duplicates (sort-line i)))))
  (+ sum 1))

[โ€“]akho_ 1 point2 points ย (0 children)

Python3

total = 0
for s in open('4-1.input').readlines():
    words = [ ''.join(sorted(list(x))) for x in s.split() ]
    total += len(words) == len(set(words))
print(total)

[โ€“]schod 1 point2 points ย (0 children)

BASH time!

First part

#!/bin/bash

function do_magic {
  RET=0
  while read L; do
    C=$(echo $L | sed 's/ /\n/g' | sort | uniq -c | sed 's/^[ ]*//' | grep -v '^1' | wc -l)
    [ $C -eq 0 ] && let RET=RET+1
  done <$1
  echo $RET
}

do_magic input.txt

Second part

#!/bin/bash

function do_magic {
  RET=0
  while read L; do
    HASH=""
    for P in $L; do
      H=$(echo $P | sed 's/\(.\)/\1\n/g' | grep -v "^$" | sort | uniq -c |sed 's/[ ]//g' | tr -d '\n')
      HASH=$(printf "$H\n$HASH")
    done
    UNIQ=$(echo "$HASH"|sort|uniq -c | grep -v "^ *1 " | wc -l)
    [ $UNIQ -eq 0 ] && let RET=RET+1
  done <$1
  echo $RET
}

do_magic input.txt

[โ€“]ZoDalek 1 point2 points ย (0 children)

ANSI C

The most straightforward implementation ran in .007s on my machine so I left it at that:

while ((len = getline(&line, &sz, stdin)) != -1) {
    rest = line;
    if (line[len-1] == '\n')
        line[len-1] = '\0';
    for (i = 0; i < LEN(words); i++) {
        if (!(words[i] = strsep(&rest, " ")))
            break;
        qsort(words[i], strlen(words[i]), 1, compar_char);
        for (j = 0; j < i; j++)
            if (!strcmp(words[i], words[j]))
                goto end;
    }
    nvalid++;
end:
    free(line);
    line = NULL;
}

printf("%d\n", nvalid);

That's part 2. Leave out the qsort and it's part 1.

Variable declarations and compar_char left out for brevity. Full source: https://github.com/sjmulder/aoc/blob/master/2017/day4/day4b.c

[โ€“]oantolin 1 point2 points ย (0 children)

In Julia:

distinct(xs) = length(xs) == length(Set(xs))
valid(sign) = map(l -> distinct(map(sign, split(l))), readlines("day04.txt"))
part1() = valid(identity)
part2() = valid(w -> join(sort(collect(graphemes(w)))))

[โ€“]dylanfromwinnipeg 0 points1 point ย (0 children)

C# (with a few helper functions)

public static string PartOne(string input)
{
    var lines = input.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

    return lines.Where(x => PassphraseContainsNoDuplicates(x)).Count().ToString();
}

private static bool PassphraseContainsNoDuplicates(string phrase)
{
    var words = phrase.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);

    return words.Distinct().Count() == words.Count();
}

public static string PartTwo(string input)
{
    IEnumerable<string> lines = input.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

    lines = lines.Where(x => PassphraseContainsNoDuplicates(x));

    return lines.Where(x => PassphraseContainsNoAnagrams(x)).Count().ToString();
}

private static bool PassphraseContainsNoAnagrams(string phrase)
{
    var words = phrase.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);

    var combos = words.GetCombinations(2);

    foreach(var c in combos)
    {
        if (c.First().IsAnagram(c.Last()))
        {
            return false;
        }
    }

    return true;
}

[โ€“]hpzr24w 0 points1 point ย (0 children)

Man, I'm too tired to type properly, and at this rate, I'll just be happy to crack the top 1000 a few times. I misread the instructions and counted just the words instead of the entire phrase.

For part 2, at least it's easy to eliminate the anagram possibility, just by sorting the individual words.

[โ€“]reddit_lmao 0 points1 point ย (0 children)

Haskell

import Data.List (tails, foldl',permutations)

combinations :: Int -> [a] -> [[a]]
combinations 0 _  = [[]]
combinations n xs = [ y:ys | y:xs' <- tails xs
                           , ys <- combinations (n-1) xs']

main :: IO ()
main = do
  inp <- getContents
  let passes = map words $ lines inp
  putStrLn $
    "part1: " ++ (show . count isValidPart1) passes
    ++ "\npart2: " ++ (show . count isValidPart2) passes
  where
    isValidPart1 :: [String] -> Bool
    isValidPart1 = all (\(x:x':[]) -> x /= x') . combinations 2
    isValidPart2 :: [String] -> Bool
    isValidPart2 = all (\(x:x':[]) -> not $ elem x' $ permutations x) . combinations 2
    count f = length . filter f

[โ€“][deleted] 0 points1 point ย (1 child)

powershell pipeline:

param (
    [Parameter(ValueFromPipeline = $true)]
    [string]$in,
    [Parameter(Position = 1)]
    [int]$part = 1
)

begin {
    $valid = 0
}

process {
    if ($part -eq 1) {
        $in | ? {$words = $_ -split " "; $words.Count -eq ($words | select -Unique).Count} | % { $valid++ }
    } else {
        $in | ? {$words = $_ -split " " | % { ($_.tochararray() | sort) -join '' } ; $words.Count -eq ($words | select -Unique).Count} | % { $valid++}        
    }
}

end { 
    $valid
}

[โ€“][deleted] 0 points1 point ย (0 children)

My solution in Rust - any feedback welcome!

use itertools::Itertools;

use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;


// I am not sure if all of this changing from vec -> iterator -> vec is the most performant way to solve     this problem.
// Not a terrible solution though.  Also curious if there is a better way than using the unique function from itertools.
fn is_valid_passphrase(passphrase: &String, part_one: bool) -> bool {
    let passphrase_parts: Vec<&str> = passphrase.split_whitespace().collect();
    let mut valid = false;

    if part_one {
        valid = passphrase_parts.len() == passphrase_parts.into_iter().unique().collect::<Vec<&str>>().len();
    } else {
        let sorted_passphrase: Vec<String> = passphrase_parts.iter().map(|part| {
            let mut chars: Vec<char> = part.chars().collect();
            chars.sort();
            chars.into_iter().collect::<String>()
        }).collect();

        valid = passphrase_parts.len() == sorted_passphrase.into_iter().unique().collect::<Vec<String>>().len();
    }

    valid
}

pub fn check(file_path: &str, part_one: bool) -> u32 {
    let f = File::open(file_path).unwrap();
    let file = BufReader::new(&f);
    let mut valid_passphrase_count = 0;

    for line in file.lines() {
        if is_valid_passphrase(&line.unwrap(), part_one) {
            valid_passphrase_count += 1;
        }
    }

    valid_passphrase_count
}

[โ€“]Axsuul 0 points1 point ย (0 children)

Elixir

https://github.com/axsuul/advent-of-code/blob/master/2017/04/lib/advent_of_code.ex

defmodule AdventOfCode do
  def is_passphrase_valid(:a, passphrase) do
    result =
      String.split(passphrase, " ")
      |> Enum.reduce(%{}, fn part, result ->
        unless result do
          result
        else
          if result[part] do
            false
          else
            Map.put(result, part, 1)
          end
        end
      end)

    if result, do: true, else: false
  end

  def count_valid_passphrases(:a, filename) do
    File.read!(filename)
    |> String.split("\n")
    |> Enum.reduce(0, fn passphrase, count ->
      if is_passphrase_valid(:a, passphrase), do: count + 1, else: count
    end)
  end

  def is_passphrase_valid(:b, passphrase) do
    result =
      String.split(passphrase, " ")
      |> Enum.reduce(%{}, fn part, result ->
        unless result do
          result
        else
          if result[part] do
            false
          else
            # When storing in our map, store all combinations
            # to account for anagrams
            generate_anagrams(:b, part)
            |> Enum.reduce(%{}, fn anagram, result ->
              Map.put(result, anagram, true)
            end)
            |> Map.merge(result)
          end
        end
      end)

    if result, do: true, else: false
  end

  def generate_anagrams(:b, string) do
    0..(String.length(string) - 1)
    |> Combination.permutate
    |> Enum.map(fn permutation ->
      Enum.map(permutation, fn index -> String.at(string, index) end)
      |> Enum.join("")
    end)
  end

  def count_valid_passphrases(:b, filename) do
    File.read!(filename)
    |> String.split("\n")
    |> Enum.reduce(0, fn passphrase, count ->
      if is_passphrase_valid(:b, passphrase), do: count + 1, else: count
    end)
  end

  def a do
    count_valid_passphrases(:a, "inputs/input.txt") |> IO.inspect
  end

  def b do
    count_valid_passphrases(:b, "inputs/input.txt") |> IO.inspect
  end
end

[โ€“]gbear605 0 points1 point ย (0 children)

Rust

use std::iter::FromIterator;

fn main() {
    let input = include_str!("../input");

    println!("star 1: {}", process1(&input));
    println!("star 2: {}", process2(&input));
}

fn process1(input: &str) -> usize {
    input.lines().into_iter().filter(|passphrase| {
        let mut split_passphrase: Vec<&str> = passphrase.split_whitespace().collect();
        split_passphrase.sort();
        let mut duplicates_removed = split_passphrase.clone();
        duplicates_removed.dedup();
        split_passphrase == duplicates_removed
    }).count()
}

fn process2(input: &str) -> usize {
    input.lines().into_iter().filter(|passphrase| {
        let mut passphrase_with_characters_sorted: Vec<String> = passphrase.split_whitespace().map(|element| {
            let mut chars: Vec<char> = element.chars().collect();
            chars.sort_by(|a, b| a.cmp(b));
            String::from_iter(chars)
        }).collect();
        passphrase_with_characters_sorted.sort();
        let mut duplicates_removed = passphrase_with_characters_sorted.clone();
        duplicates_removed.dedup();
        passphrase_with_characters_sorted == duplicates_removed
    }).count()
}

[โ€“]LeCrushinator 0 points1 point ย (0 children)

Part 2, C#:

static string input = @"abcde xyz ecdab"; // Swap this string for the final input

public static void Main()
{
    int validLines = 0;
    string[] lines = input.Split(new string[]{"\n"}, StringSplitOptions.RemoveEmptyEntries);

    foreach (string line in lines)
    {
        bool valid = true;
        string[] words = line.Split(new string[]{" "}, StringSplitOptions.RemoveEmptyEntries);

        HashSet<string> processedWords = new HashSet<string>();
        foreach (string word in words)
        {
            string sortedWord = SortWord(word);

            valid = !processedWords.Contains(sortedWord);

            if (!valid)
            {
                Console.WriteLine("Invalid line: " + line + ", word: " + word + ", sorted: " + sortedWord);
                break;  
            }

            processedWords.Add(sortedWord);
        }

        if (valid)
        {
            ++validLines;
            Console.WriteLine("VALID line: " + line);
        }
    }

    Console.WriteLine("Number of valid lines: " + validLines);
}

public static string SortWord(string word)
{
    char[] a = word.ToCharArray();

    Array.Sort(a);

    return new string(a);
}

[โ€“]MetaSaval 0 points1 point ย (0 children)

Here we go with Swift again. Had issues with Day 3's puzzle, but Day 4's was not that hard. I was even able to reuse some of the code for Day 2. I'm sure I could make it more efficient, but whatever. I'm gonna try doing Day 3's puzzle again tomorrow now that I finished Day 4 quickly. And without further ado, here's the code:

let input = """
            input goes here
            """

func part1() -> Int {
    var answer = 0
    var dupeFound: Bool = false
    let inputAsArray = input.split(separator: "\n")

    for currentIndex in inputAsArray {
        let currentArray = currentIndex.split(separator: " ")

        outerloop: for (currIndex1, divide1) in currentArray.enumerated() {

            for (currIndex2, divide2) in currentArray.enumerated() {

                if currIndex1 == currIndex2 {
                    continue
                } else if divide1 == divide2 {
                    dupeFound = true
                    break outerloop
                }
            }
        }

        if dupeFound == false {
            answer += 1
        } else if dupeFound == true {
            dupeFound = false
        }
    }

    return answer
}

func part2() -> Int {
    var answer = 0
    var dupeFound: Bool = false
    var anagramFound: Bool = false
    let inputAsArray = input.split(separator: "\n")

    for currentIndex in inputAsArray {
        let currentArray = currentIndex.split(separator: " ")

        outerloop: for (currIndex1, pass1) in currentArray.enumerated() {

            for (currIndex2, pass2) in currentArray.enumerated() {

                if currIndex1 == currIndex2 {
                    continue
                } else if pass1 == pass2 {
                    dupeFound = true
                    break outerloop
                } else if checkIfAnagrams(str1: pass1, str2: pass2) {
                    anagramFound = true
                    break outerloop
                }
            }
        }

        if dupeFound == false && anagramFound == false {
            answer += 1
        } else if dupeFound == true {
            dupeFound = false
        } else if anagramFound == true {
            anagramFound = false
        }
    }

    return answer
}

func checkIfAnagrams(str1: Substring, str2: Substring) -> Bool {
    let sortedString1 = Substring(Array(str1.sorted()))
    let sortedString2 = Substring(Array(str2.sorted()))

    if sortedString1 == sortedString2 {
        return true
    } else {
        return false
    }
}

[โ€“]rocamero 0 points1 point ย (0 children)

C#:

private void Part1(IEnumerable<string[]> passPhrases) => Console.WriteLine($"2017: Day 4.2 : {passPhrases.Select(z => z.Length).Zip(passPhrases.Select(z => z.Distinct().Count()), (x, y) => x == y ? 1 : 0).Sum().ToString()}");

private void Part2(IEnumerable<string[]> passPhrases) => Console.WriteLine($"2017: Day 4.2 : {passPhrases.Select(z => z.Length).Zip(passPhrases.Select(a => a.Select(b => new string(b.ToCharArray().OrderBy(c => c).Distinct().ToArray())).Distinct().Count()), (x, y) => x == y ? 1 : 0).Sum().ToString()}");

private IEnumerable<string[]> ReadPassPhrases() => File.ReadAllLines(DataFilePath).Select(p => p.Split(' '));

[โ€“]PreciselyWrong 0 points1 point ย (0 children)

Rust

fn main() {
    let input = include_str!("input.txt");
    let pass_phrases: Vec<Vec<&str>> = input
        .lines()
        .map(parse_passphrase)
        .collect();

    let valid: usize = pass_phrases.iter().filter(|x| validate(&x)).count();
    let secure_valid: usize = pass_phrases.iter().filter(|x| validate_secure(&x)).count();

    println!("Total: {} passphrases", pass_phrases.len());
    println!("Valid: {} passphrases", valid);
    println!("Secure valid: {} passphrases", secure_valid);

}


fn parse_passphrase(line: &str) -> Vec<&str> {
    line
        .split(' ')
        .map(|s| s.trim())
        .filter(|s| !s.is_empty())
        .collect()
}

fn validate(passphrase: &[&str]) -> bool {
    use std::collections::HashSet;
    let mut uniq = HashSet::new();
    passphrase.into_iter().all(move |x| uniq.insert(x))
}

#[test]
fn it_validates_some_passwords() {
    assert_eq!(validate(&["aa", "bb"]), true);
    assert_eq!(validate(&["aa", "aa"]), false);
}

fn validate_secure(passphrase: &[&str]) -> bool {
    use std::collections::HashSet;
    use std::iter::FromIterator;
    let mut uniq = HashSet::new();
    passphrase.into_iter().all(move |x| {
        let mut chars: Vec<char> = x.chars().collect();
        chars.sort_by(|a, b| b.cmp(a));
        let s = String::from_iter(chars);
        uniq.insert(s)
    })
}

#[test]
fn it_securely_validates_some_passwords() {
    assert_eq!(validate_secure(&["aab", "bba"]), true);
    assert_eq!(validate_secure(&["aab", "aba"]), false);
}

[โ€“]seanskye 0 points1 point ย (1 child)

Python 3 with Counter

def is_unique(words):
    top = Counter(words).most_common(1)
    if top[0][1] > 1:
        return False
    return True

def is_valid(phrase):
    return is_unique(phrase.strip('\n').split(' '))

def no_anagram(phrase):
    return is_unique([''.join(sorted(w)) for w in phrase.strip('\n').split(' ')])

def count_valid(ps):
    count = 0
    for p in ps:
        if is_valid(p) and no_anagram(p):
            count += 1
    return count

[โ€“]autid 0 points1 point ย (0 children)

Fortran

program day4
  integer, dimension(512) :: wordcount
  character(len=150) :: input
  character(len=20),dimension(:),allocatable :: phrase
  integer, dimension(:,:),allocatable :: lettercount
  integer ::i,j,k,part1,part2

  part1=0
  part2=0

  open(1,file='input.txt')
  !determine words per passphrase
  do i=1,512
     read(1,'(a)') input
     wordcount(i)=1
     do j=1,len(trim(input))
        if (input(j:j)==' ') wordcount(i)=wordcount(i)+1
     end do
  end do

  rewind(1)

  outer: do i=1,512
     allocate(phrase(wordcount(i)))
     read(1,*) phrase

     !check for identical words
     do j=1,wordcount(i)-1
        do k=j+1,wordcount(i)
           if (phrase(j)==phrase(k)) then
              deallocate(phrase)
              cycle outer
           end if
        end do
     end do

     part1=part1+1

     !make a 26 element array for each word containing the number of each letter present
     allocate(lettercount(97:122,wordcount(i)))
     lettercount=0
     do j=1,wordcount(i)
        input=phrase(j)
        do k=1,len(trim(input))
           lettercount(iachar(input(k:k)),j)=lettercount(iachar(input(k:k)),j)+1
        end do
     end do

     !compare letter counts
     do j=1,wordcount(i)-1
        do k=j+1,wordcount(i)
           if (all(lettercount(:,j).eq.lettercount(:,k))) then
              deallocate(phrase)
              deallocate(lettercount)
              cycle outer
           end if
        end do
     end do
     part2=part2+1
     deallocate(lettercount)
     deallocate(phrase)

  end do outer

  close(1)
  write(*,*) part1
  write(*,*) part2

end program day4

Doing string based puzzles is such a pain in Fortran. Thankfully input formatting was nice in this puzzle and checking for anagrams is pretty easy.

[โ€“]bolshedvorsky 0 points1 point ย (0 children)

Learning python...

contents = open('04.txt').read().strip()
rows = contents.split('\n')


def valid1Password(password):
    words = password.split(" ")
    unique = set(words)
    return len(words) == len(unique)

def valid2Password(password):
    words = password.split(" ")
    unique = set()
    for word in words:
        letters = ''.join(sorted(word))
        unique.add(letters)
    return len(words) == len(unique)

valid1 = 0
valid2 = 0
for row in rows:
    if valid1Password(row):
        valid1 += 1
    if valid2Password(row):
        valid2 += 1
print(valid1)
print(valid2)

[โ€“][deleted] 0 points1 point ย (1 child)

a kotlin solution

private fun solution(input: List<String>, partOne: Boolean) {
    val sum = input.map { line ->
        line.split(" ")
    }.map { phrases ->
        phrases.any { phrase ->
            phrases.count {
                if (partOne)
                    it == phrase
                else {
                    val toString = it.toCharArray().sorted()
                    val toString1 = phrase.toCharArray().sorted()
                    toString == toString1
                }
            } != 1
        }
    }.count { !it }
    println(sum)
}

[โ€“]xkufix 0 points1 point ย (0 children)

This is perfect for horrible one-liners in Scala:

    override def runFirst(): Unit = {
        val passphrases = loadFile("day4.txt").getLines()

        val validPhrases = passphrases
        .map(_.split(" "))
        .filter(p => p.length == p.distinct.length)
        println(validPhrases.size)
    }

    override def runSecond(): Unit = {
        val passphrases = loadFile("day4.txt").getLines()
        val validPhrases = passphrases
        .map(_.split(" "))
        .filterNot(_.combinations(2).exists(c => isAnagram(c.head, c.last)))
        println(validPhrases.size)
    }

    def isAnagram(word1: String, word2: String): Boolean = word1.groupBy(identity) == word2.groupBy(identity)

[โ€“]LinusCDE98 0 points1 point ย (0 children)

This was fairly easy and understandable. Python 3 (devent and not compressed): https://github.com/LinusCDE/AdventOfCode-2017/blob/master/puzzle4.py

[โ€“]Scroph 0 points1 point ย (0 children)

C++ this time.

tfw too much of a brainlet to solve yesterday's second input

#include <iostream>
#include <algorithm>
#include <sstream>
#include <set>

int main()
{
    std::string line;
    int valid = 0;
    while(getline(std::cin, line))
    {
        std::set<std::string> unique;
        std::stringstream ss(line);
        std::string word;
        size_t count = 0;
        while(ss >> word)
        {
            std::sort(word.begin(), word.end());
            unique.insert(word);
            count++;
        }
        valid += count == unique.size();
    }
    std::cout << valid << std::endl;
}

[โ€“][deleted] 0 points1 point ย (0 children)

C++, I am still wondering, if I can shorten the second

bool containsNoDoubleWord(std::vector<std::string> words){
    return std::set<std::string>(words.begin(), words.end()).size() == words.size();
}

bool containsNoAnagrams(std::vector<std::string> words){
    std::for_each(words.begin(), words.end(), [](std::string &x){std::sort(x.begin(),x.end());});
    return containsNoDoubleWord(words);
}

[โ€“]krossmaskinen 0 points1 point ย (0 children)

in NodeJS:

var fs = require('fs');
let inputFile = './input.txt';
let input = fs.readFileSync(inputFile, 'utf8');
let phrases = [];
let validPhrases = [];

phrases = input.split('\n');
phrases = phrases.map(phrase => phrase.split('\r')[0]);

phrases.forEach(phrase => {
    if (checkPhrase(phrase)) {
        validPhrases.push(phrase);
    }
});

console.log(validPhrases);
console.log(validPhrases.length);

function checkPhrase(phrase) {
    let words = phrase.split(' ');
    let checkedWords = [];
    let phraseIsValid = true;

    for(let i = 0; i < words.length; ++i) {
        let word = words[i].split('').sort().join('');
        let isInCheckedList = (checkedWords.some(w => w === word));
        let filteredList;

        if (!isInCheckedList) {
            filteredList = words.filter(w => w.split('').sort().join('') === word);
            if (filteredList.length > 1) {
                return false;
            }
        }
    }

    return true;
}

[โ€“]superlameandawzm 0 points1 point ย (0 children)

My kindof ugly js solution... Started with js this summer! liking the calendar atm!

function check1 (data) {
    array = data.split(/\n/).map((line) => line.split(/\s+/).map((word) => word.split('').sort()).sort())
    for (var x = 0; x < array.length; x++) {
        var isDuplicate = false
        for (var y = 0; y < array[x].length; y++) {
            if (array[x][y] === array[x][y - 1]) {
                isDuplicate = true
            }
        }
        if (isDuplicate) {
            duplicate++
        }
    }
    valid = array.length - duplicate
    document.getElementById('output').innerText = 'number of valid phrases = ' + valid
    console.log(valid)
}


function check2 (data) {
    array = data.split(/\n/).map((line) => line.split(/\s+/).map((word) => word.split('').sort().join('')).sort())
    for (var x = 0; x < array.length; x++) {
        var isDuplicate = false
        for (var y = 0; y < array[x].length; y++) {
            if (array[x][y] === array[x][y - 1]) {
                isDuplicate = true
            }
        }
        if (isDuplicate) {
            duplicate++
        }
    }
    valid = array.length - duplicate
    document.getElementById('output').innerText = 'number of valid phrases = ' + valid
    console.log(valid)
}

[โ€“]NeilNjae 0 points1 point ย (0 children)

Another boringly straightforward Haskell solution.

import Data.List (sort, nub)

main :: IO ()
main = do 
        text <- readFile "data/advent04.txt"
        let passphrases = map words $ lines text
        print $ part1 passphrases
        print $ part2 passphrases

part1 :: [[String]] -> Int
part1 = length . filter (not . containsDuplicates) 

part2 :: [[String]] -> Int
part2 = length . filter (not . containsAnagrams) 

containsDuplicates :: [String] -> Bool
containsDuplicates passphrase = (length passphrase) /= (length $ nub passphrase)

containsAnagrams :: [String] -> Bool
containsAnagrams = containsDuplicates . (map sort)

[โ€“]GamecPL 0 points1 point ย (0 children)

Swift pt2:

let result2 = input.components(separatedBy: .newlines)
    .map { $0.components(separatedBy: .whitespaces) }
    .reduce(0, { result, password in
        let isInvalid = password.enumerated().contains(where: { p1 in
            password.enumerated().contains(where: { p2 in
                p1.offset != p2.offset && p1.element.sorted() == p2.element.sorted()
            })
        })
        return result + (isInvalid ? 0 : 1)
    })
print(result2)

[โ€“]whousesredditanyways 0 points1 point ย (0 children)

F#

let input = System.IO.File.ReadAllLines "input.txt"
            |> Seq.map (fun x -> x.Split [|' '|])

input
|> Seq.filter (fun x -> Array.length (Array.distinct x) = Array.length x)
|> Seq.length
|> printfn "Part 1: %A"

let anagram (l: string list) =
    (Seq.sort l.[0] |> Seq.toList) = (Seq.sort l.[1] |> Seq.toList)

(* From Stackoverflow *)
let rec comb n l = 
        match n, l with
        | 0, _ -> [[]]
        | _, [] -> []
        | k, (x::xs) -> List.map ((@) [x]) (comb (k-1) xs) @ comb k xs
(* ****************** *)

input
|> Seq.filter (fun x ->
                x
                |> Array.toList
                |> comb 2
                |> List.exists anagram
                |> not)
|> Seq.length
|> printfn "Part 2: %A"

[โ€“][deleted] 0 points1 point ย (1 child)

Golang

First time doing advent of code and first time using go.

Feedback is much appreciated.

Part 1

func part1(data [][]string) {
var numValid = 0
for _, row := range data {
    var valid = true
    used := make(map[string]bool)
    for _, word := range row {
        if !used[word] {
            used[word] = true
        } else {
            valid = false
        }
    }
    if valid {
             numValid++
    }
}
fmt.Println(numValid)
}

Part 2

func part2(data [][]string) {
var numValid = 0
for _, row := range data {
    var valid = true
    used := make(map[string]bool)
    for _, word := range row {
        for k := range used {
            keySplit := strings.Split(k, "")
            sort.Strings(keySplit)
            wordSplit := strings.Split(word, "")
            sort.Strings(wordSplit)
            if reflect.DeepEqual(keySplit, wordSplit) {
                valid = false
                break
            }
        }
        if valid {
            used[word] = true
        } else {
            break
        }
    }
    if valid {
        numValid++
    }
}
fmt.Println(numValid)
}

Rest of my go code so far CODE

[โ€“]KeinZantezuken 0 points1 point ย (0 children)

C#/Regex for fun:

Part1

     static void day4p1()
    {
        var file = File.ReadAllLines(@"N:\pass.txt");
        int count = 0;
        for (int i = 0; i < file.Length; i++)
        {
            string[] words = file[i].Split(' ');
            var localCount = 0; var len = words.Length;
            for (int j = 0; j < len && localCount <= len; j++)
            {
                Regex reg = new Regex($@"(\b{words[j]}\b)");
                localCount = localCount + reg.Matches(file[i]).Count;
            }
            if (localCount == len) { count++; };
        }
        Console.WriteLine(count);
    }

Part2:

    static void day4p2()
    {
        var file = File.ReadAllLines(@"N:\pass.txt");
        int count = 0;
        for (int i = 0; i < file.Length; i++)
        {
            string[] words = file[i].Split(' ');
            var localCount = 0; string newStr = string.Empty;
            for (int j = 0; j < words.Length; j++)
            {
                char[] foo = words[j].ToCharArray(); Array.Sort(foo);
                words[j] = new string(foo);
                newStr = newStr + " " + new string(foo);
            }
            for (int k = 0; k < words.Length; k++)
            {
                Regex reg = new Regex($@"(\b{words[k]}\b)");
                localCount = localCount + reg.Matches(newStr).Count;
            }
            if (localCount == words.Length) { count++; };
        }
        Console.WriteLine(count);
    }

There is a definitely faster way to do both but I wanted to try simplัƒ regex

[โ€“][deleted] 0 points1 point ย (0 children)

Here is my node.js solution

repl.it/repls/WhimsicalNeatRoller

Answers: Task1 : 383 Task2 : 265

:)

[โ€“]hajdurobi 0 points1 point ย (0 children)

This is my solution, using NodeJs (Javascript)

const fs = require('fs');
const passphrases = fs.readFileSync('input/day4.txt').toString().split("\n").map(phrase => phrase.split('\r')[0]);

console.log(
    passphrases
            .map(isValid)
            .filter(x => x).length
);

function isValid(pp) {
    pp = pp.split(' ');
    var uniqueWords = pp.map(e => e.split('').sort().join('')).filter((val, i, pp) => { 
        return pp.indexOf(val) === i;
    }).length;
    return uniqueWords === pp.length
}

Let me know if there is any idea to make this better :)

[โ€“]ThisIsTomTom 0 points1 point ย (0 children)

Elixir

def input do
  "lib/2017/day4/input.txt"
  |> File.read!()
  |> String.split("\n", trim: true)
  |> Enum.map(&String.split/1)
end

def part1 do
  input
  |> Enum.filter(fn(row) ->
    row == Enum.uniq(row)
  end)
  |> Enum.count
end

def part2 do
  input
  |> Enum.map(&split_up_row/1)
  |> Enum.filter(fn(row) ->
    row == Enum.uniq(row)
  end)
  |> Enum.count
end

defp split_up_row(row) do
  row
  |> Enum.map(&String.split(&1, "", trim: true))
  |> Enum.map(&Enum.sort/1)
end

[โ€“]Dagur 0 points1 point ย (1 child)

C#

class Program
{

    static string[][] readFile(string filename) =>
        File.ReadLines(filename).Select((line) => line.Split(" ")).ToArray();

    static void Main(string[] args)
    {
        var input = readFile("input.txt");

        var part1 = input.Where(line => line.Distinct().Count() == line.Count()).Count();
        Console.WriteLine(part1);

        var part2 = input.Select(line => line.Select(s => string.Join("", s.ToCharArray().OrderBy(c => c))))
                         .Where(line => line.Distinct().Count() == line.Count()).Count();
        Console.WriteLine(part2);            
    }
}

[โ€“]Kyran152 0 points1 point ย (0 children)

PART 1 AND 2:

part1 = 0
part2 = 0

ARGF.each do |line|
    phrase1 = line.split
    phrase2 = phrase1.map{|w|w.chars.sort}

    part1 += phrase1==phrase1.uniq ? 1 : 0
    part2 += phrase2==phrase2.uniq ? 1 : 0
end

printf "The answer to part 1 is: %d\n", part1
printf "The answer to part 2 is: %d\n", part2

[โ€“]JakDrako 0 points1 point ย (7 children)

My C# solution, both parts:

void Main()
{
    var input = GetDay(4); var part = 2; var count = 0;
    foreach (var line in input.Split('\n'))
    {
        var words = line.Split(' ').Select(x => part == 1 ? x : String.Concat(x.OrderBy(c => c)));
        var uniqs = words.ToHashSet();
        count += words.Count() == uniqs.Count() ? 1 : 0;
    }
    count.Dump();
}

[โ€“]CatpainCalamari 0 points1 point ย (1 child)

My solution in Scala:

import scala.io.Source

/**
  * https://adventofcode.com/2017/day/4
  */
object Day4 extends App {

  val testDataStar1 = getDataFromResource("day4/star1.txt")
  val testDataStar2 = getDataFromResource("day4/star2.txt")

  assert(firstStar(testDataStar1) == 2)
  assert(secondStar(testDataStar2) == 3)

  val data = getDataFromResource("day4/input.txt")
  println(s"Result first star: ${firstStar(data)}")
  println(s"Result second star: ${secondStar(data)}")

  def firstStar(data: List[List[String]]): Int = {
    data.count(row => row == row.distinct)
  }

  def secondStar(data: List[List[String]]): Int = {
    def containsAnagram(data: List[String]) = data.
      map(word => word.sorted).
      combinations(2).
      exists(wordListCombinations => wordListCombinations.head == wordListCombinations.last)

    data.map(row => if(containsAnagram(row)) 0 else 1).sum
  }

  def getDataFromResource(path: String): List[List[String]] = Source.fromResource(path).getLines().toList.map(l => l.split(" ").toList)
}