10
\$\begingroup\$

I got into code-golfing recently and tried to write the smallest tautogram checker.

A tautogram is a sentence in which all words start with the same letter, for example: Flowers flourish from France.

Given a sentence as input, determine whether it is a tautogram.

Test Cases

Flowers flourish from France
    True

This is not a Tautogram
    False

I came up with this python code (because it is my main language):

print(True if len(list(set([x.upper()[0] for x in __import__('sys').argv[1:]]))) == 1 else False)

Usage:

python3 tautogram.py Flowers flourish from France
# True
python3 tautogram.py This is not a Tautogram
# False

The sentence may contain commas and periods, but no other special characters, only upper and lower case letters and spaces.

Its size is 98 bytes. Is there a smaller solution in any language?

\$\endgroup\$

closed as unclear what you're asking by Erik the Outgolfer, Stephen, Embodiment of Ignorance, Don Thousand, Jonathan Allan Mar 25 at 22:26

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    \$\begingroup\$ Is it intended as a tips question limited to Python? If so, these both tags should be added. \$\endgroup\$ – Arnauld Mar 25 at 19:26
  • 2
    \$\begingroup\$ Heya friend! This site is usually reserved for explicitly defined problems. Things like "can the input contain punctuation" should be answered before posting, but other than that this is a great first question comparatively to the other new-user questions we usually see. Judging by your examples I'd just clarify that the only characters in the input will be "[A-Za-z ]" and your question will be purely objective. I'd scope out some other questions around here, else this may honestly be a better fit on overflow. \$\endgroup\$ – Magic Octopus Urn Mar 25 at 19:27
  • 1
    \$\begingroup\$ What do you mean by punctuation? Which characters are included? \$\endgroup\$ – Embodiment of Ignorance Mar 25 at 19:35
  • 1
    \$\begingroup\$ @MagicOctopusUrn Sometimes when you ask for a short solution in stackOverflow the refer to this site :) \$\endgroup\$ – Luis felipe De jesus Munoz Mar 25 at 19:45
  • 6
    \$\begingroup\$ Welcome to PPCG! A few more test cases (including punctuation) would be a great addition to this challenge. \$\endgroup\$ – AdmBorkBork Mar 25 at 20:10

13 Answers 13

7
\$\begingroup\$

05AB1E, 5 bytes

l#€нË

Try it online!


l      # Lowercase input.
 #     # Split on spaces.
  €н   # a[0] of each.
    Ë  # All equal?

Did this on mobile excuse the no explanation.

\$\endgroup\$
4
\$\begingroup\$

Python 2, 47 bytes

lambda s:len(set(zip(*s.lower().split())[0]))<2

Try it online!

Came up with this on mobile. Can probably be golfed more.

\$\endgroup\$
3
\$\begingroup\$

Clojure, 80 bytes

Try it online!. TIO doesn't support Clojure's standard String library though, so the first version will throw a "Can't find lower-case" error.

(fn[s](use '[clojure.string])(apply =(map first(map lower-case(split s #" ")))))

Ungolfed:

(defn tautogram? [s]
  (use '[clojure.string])
  (->> (split s #" ") ; Get words
       (map lower-case)
       (map first) ; Get first letter of each word
       (apply =))) ; And make sure they're all the same

I made a version that avoids the import:

(fn [s](apply =(map #(if(<(-(int %)32)65)(int %)(-(int %) 32))(map first(take-nth 2(partition-by #(= %\ )s))))))

 ; -----

(defn tautogram? [s]
  (->> s
       (partition-by #(= % \ )) ; Split into words
       (take-nth 2) ; Remove spaces
       (map first) ; Get first letter
       ; Convert to uppercased letter code
       (map #(if (< (- (int %) 32) 65) ; If attempting to uppercase puts the letter out of range,
               (int %) ; Go with the current code
               (- (int %) 32))) ; Else go with the uppercased  code
       (apply =))) ; And check if they're all equal

But it's 112 Bytes.

\$\endgroup\$
  • \$\begingroup\$ Here's my Racket solution: (define(f s)(apply char=?(map(λ(x)(char-upcase(car(string->list x))))(string-split s)))) \$\endgroup\$ – Galen Ivanov Mar 26 at 7:18
  • \$\begingroup\$ Much shorter in PicoLisp: (de f(s)(apply =(mapcar car(split(chop(lowc s))" ")))) \$\endgroup\$ – Galen Ivanov Mar 26 at 7:47
3
\$\begingroup\$

PowerShell, 57 50 41 bytes

(-split$args|% s*g 0 1|sort -u).count-eq1

Try it online!

Takes input and splits it on whitespace. Loops through each word, and grabs the first letter by taking the substring starting at position 0 and going for 1 character. Then sorts the letters (case-insensitive by default) with the -unique flag to pull out only one copy of each letter, and verifies the count of those names are -equal to 1. Output is implicit.

-9 bytes thanks to mazzy.

\$\endgroup\$
  • \$\begingroup\$ 41 bytes \$\endgroup\$ – mazzy Mar 26 at 5:43
  • \$\begingroup\$ 35 bytes with regexp \$\endgroup\$ – mazzy Mar 26 at 8:01
  • 1
    \$\begingroup\$ @mazzy fixed trying to understand the intention \$\endgroup\$ – Nahuel Fouilleul Mar 26 at 8:36
  • \$\begingroup\$ @mazzy I'll let you post the regex version when the question is reopened. It's different enough to warrant its own answer. \$\endgroup\$ – AdmBorkBork Mar 26 at 12:29
  • \$\begingroup\$ I'm agree. but this question is put on hold, so I can't create a new answer. \$\endgroup\$ – mazzy Mar 26 at 15:27
2
\$\begingroup\$

05AB1E (legacy), 5 bytes

#€¬uË

Try it online!

#     // split on spaces
 €¬   // get the first letter of each word
   uË // check if they're the same (uppercase) letter
\$\endgroup\$
2
\$\begingroup\$

Brachylog, 5 bytes

ḷṇ₁hᵛ

Try it online!

         The input
ḷ        lowercased
 ṇ₁      and split on spaces
   hᵛ    is a list of elements which all start with the same thing.
\$\endgroup\$
  • \$\begingroup\$ I just now noticed that this has to be able to handle punctuation, but without any punctuated test cases I can't tell if this does or doesn't still work... \$\endgroup\$ – Unrelated String Mar 25 at 22:13
2
\$\begingroup\$

Haskell, 71 bytes

f s|c<-fromEnum.head<$>words s=all(`elem`[-32,0,32]).zipWith(-)c$tail c

Try it online!


Haskell, 61 58 bytes (using Data.Char.toLower)

  • Saved three bytes thanks to nimi.
import Data.Char
(all=<<(==).head).(toLower.head<$>).words

Try it online!

\$\endgroup\$
  • \$\begingroup\$ @nimi Thank you. \$\endgroup\$ – Jonathan Frech Mar 25 at 23:15
2
\$\begingroup\$

Perl 5 (-p), 20 bytes

$_=!/^(.).* (?!\1)/i

TIO

following comments in case bad punctuation (31 bytes)

$_=!/^\W*+(.).*(?=\b\w)(?!\1)/i

31 bytes

otherwise there's another approach, also with 31 bytes:

$h{ord()%32}++for/\w+/g;$_=2>%h

31 bytes other

\$\endgroup\$
  • \$\begingroup\$ what about punctuations? what about spaces or punctuations at the strart of string? \$\endgroup\$ – mazzy Mar 26 at 7:49
  • \$\begingroup\$ this answer works for the given test cases, could be improved depending the requirements could be $_=!/^\W*+(.).*(?=\b\w)(?!\1)/i \$\endgroup\$ – Nahuel Fouilleul Mar 26 at 8:06
  • \$\begingroup\$ but reading carefuly the question and the given solution, spaces at beginning can't occur because the spaces are used by the shell to split the arguments. The program checks only that all arguments start with the same character \$\endgroup\$ – Nahuel Fouilleul Mar 26 at 8:14
1
\$\begingroup\$

JavaScript (Node.js), 54 bytes

s=>!s.match(/\b\w+/g).some(p=s=>p-(p=Buffer(s)[0]&31))

Try it online!

Or 47 bytes if each word (but the first) is guaranteed to be preceded by a space.

\$\endgroup\$
  • \$\begingroup\$ or in one regex or with a space instead of \W \$\endgroup\$ – Nahuel Fouilleul Mar 25 at 20:35
  • \$\begingroup\$ @NahuelFouilleul, using test saves another byte. \$\endgroup\$ – Shaggy Mar 25 at 20:45
  • 1
    \$\begingroup\$ @NahuelFouilleul You should probably post is separately. \$\endgroup\$ – Arnauld Mar 25 at 20:55
  • \$\begingroup\$ already posted the perl version, i don't master as well javascript, i'm happy to give you a hint \$\endgroup\$ – Nahuel Fouilleul Mar 25 at 21:08
1
\$\begingroup\$

Japt , 5 bytes

¸mÎro

Try it

¸mÎro     :Implicit input of string
¸         :Split on spaces
 m        :Map
  Î       :  Get first character
   r      :Reduce by
    o     :  Keeping the characters that appear in both, case-insensitive
          :Implicit output as boolean
\$\endgroup\$
1
\$\begingroup\$

C# (Visual C# Interactive Compiler), 41 bytes

n=>n.Split().GroupBy(c=>c[0]|32).Single()

Throws an exception if false, nothing if true.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Perl 6, 19 bytes

{[eq] m:g/<<./}o&lc

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Java, (36 bytes)

s->!s.matches("(?i)(.).* (?!\\1).*")

TIO

\$\endgroup\$
  • 1
    \$\begingroup\$ I think the input is allowed to start with a space, and this doesn't work for input like that. \$\endgroup\$ – Sara J Mar 25 at 22:13
  • \$\begingroup\$ indeed it's not a test case, but this can be handled adding (?> *), using atomic group to match space at beginning and to pevent bactracking. just ` *` doesn't work because after failing matches will backtrack ` *` to match empty string \$\endgroup\$ – Nahuel Fouilleul Mar 26 at 6:32
  • \$\begingroup\$ however reading the question again spaces can occur at the beginning beause in the example the usage is to pass the words as argument and spaces are shell argument delimiter \$\endgroup\$ – Nahuel Fouilleul Mar 26 at 10:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.