3 ms·
grep { len($_) == 10 && /^[^a]*a[^a]*$/i && /^[^b]*b[^b]*$/i && /^[^c]*c[^c]*$/i && /k.$/i } @words; Is there a simpler way?
by jstanley 3y ago
grep { len($_) == 10 && /^[^a]*a[^a]*$/i && /^[^b]*b[^b]*$/i && /^[^c]*c[^c]*$/i && /k.$/i } @words;
Is there a simpler way?
- darrenf 3y agoPerl has `length`, not `len` :) Also I can't resist a bit of TIMTOWTDI: my @found = grep { local $_ = lc; length == 10 && substr($_,8,1) eq "k" && join("",sort [/([abc])/g]->@*) eq "abc" } @words;
- sltkr 3y agoMight as well do it on the command line at that point: $ grep '^........k.$' /usr/share/dict/words | grep a | grep b | grep c | grep -v 'a.*a' | grep -v 'b.*b' | grep -v 'c.*c' backstroke bailiwicks benchmarks branchlike bushwhacks greenbacks matchbooks piggybacks roadblocks scrapbooks slingbacks throwbacks thumbtacks
- cmdlineluser 3y agoNot sure if it would be considered simpler but lookaheads can be used to express it in a single pattern. ^(?=.{8}k.$)(?=[^a]*a[^a]*$)(?=[^b]*b[^b]*$)(?=[^c]*c[^c]*$)
- sltkr 3y agoIt does lead to a very concise invocation: $ perl -ne 'print if /^(?=.{8}k.$)(?=[^a]*a[^a]*$)(?=[^b]*b[^b]*$)(?=[^c]*c[^c]*$)/' /usr/share/dict/words
- shabble 3y agoand to squash a little further: perl -ne '/^(?=([abc].*){3})(?!.*([abc]).*\2).{8}k.$/&&print' /usr/share/dict/words
- oneshtein 3y agoBug: 11 words are missing. [me@fedora ~]$ time perl -ne '/^(?=([abc].*){3})(?!.*([abc]).*\2).{8}k.$/&&print' /usr/share/dict/words | wc -l 6 real 0m0,118s user 0m0,112s sys 0m0,007s
- oneshtein 3y ago[me@fedora ~]$ time perl -ne 'print if /^(?=.{8}k.$)(?=[^a]*a[^a]*$)(?=[^b]*b[^b]*$)(?=[^c]*c[^c]*$)/' /usr/share/dict/words | wc -l 17 real 0m0,250s user 0m0,245s sys 0m0,006s
- oneshtein 3y ago[me@fedora ~]$ time perl -n -e 'length($_) == 10 && /^[^a]*a[^a]*$/i && /^[^b]*b[^b]*$/i && /^[^c]*c[^c]*$/i && /k.$/i && print' /usr/share/dict/words | wc -l 26 real 0m0,168s user 0m0,162s sys 0m0,007s [me@fedora ~]$ time perl -n -e '/^(?=.{8}k.$)(?=[^a]*a[^a]*$)(?=[^b]*b[^b]*$)(?=[^c]*c[^c]*$)/ && print' /usr/share/dict/words | wc -l 17 real 0m0,260s user 0m0,254s sys 0m0,006s [me@fedora ~]$ time perl -n -e '/^.{8}k.$/ && /a/ && /b/ && /c/ && !/a.*a/ && !/b.*b/ && !/c.*c/ && print' /usr/share/dict/words | wc -l 17 real 0m0,115s user 0m0,109s sys 0m0,008s [me@fedora ~]$ time bash -c "grep '^........k.\$' /usr/share/dict/words | grep a | grep b | grep c | grep -v 'a.*a' | grep -v 'b.*b' | grep -v 'c.*c'" | wc -l 17 real 0m0,015s user 0m0,010s sys 0m0,020s [me@fedora ~]$ time awk '/^.{8}k.$/ && /a/ && /b/ && /c/ && !/a.*a/ && !/b.*b/ && ! /c.\*c/ { print }' /usr/share/dict/words | wc -l 17 real 0m0,129s user 0m0,124s sys 0m0,006s [me@fedora ~]$ time perl -n -e 'local $_ = lc; length == 11 && substr($_,8,1) eq "k" && join("",sort [/([abc])/g]->@*) eq "abc" && print' /usr/share/dict/words | wc -l 17 real 0m0,234s user 0m0,228s sys 0m0,007s
- sltkr 3y agoYou can also do: sed -e '/^........k.$/!d; /a/!d; /b/!d; /c/!d; /a.*a/d; /b.*b/d; /c.*c/d' /usr/share/dict/words I wouldn't expect it to be much faster than AWK, but not much slower either. Interesting that the pipeline is the fastest! I would expect the sheer number of separate processes to slow things down considerably, but apparently it doesn't really matter. Probably because the first `grep` already filters out most of the dictionary, so there isn't a lot of I/O through the pipes.