Is there a smaller tautogram checker?

10

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?

Jaime Tenorio

Posted 2019-03-25T19:23:45.177

Reputation: 101

Question was closed 2019-03-25T22:26:33.730

1

Is it intended as a tips question limited to Python? If so, these both tags should be added.

– Arnauld – 2019-03-25T19:26:38.623

2Heya 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. – Magic Octopus Urn – 2019-03-25T19:27:35.090

1What do you mean by punctuation? Which characters are included? – Embodiment of Ignorance – 2019-03-25T19:35:47.057

1@MagicOctopusUrn Sometimes when you ask for a short solution in stackOverflow the refer to this site :) – Luis felipe De jesus Munoz – 2019-03-25T19:45:01.253

@EmbodimentofIgnorance Commas and periods, since others are special characters – Jaime Tenorio – 2019-03-25T19:49:20.397

6Welcome to PPCG! A few more test cases (including punctuation) would be a great addition to this challenge. – AdmBorkBork – 2019-03-25T20:10:27.400

1Btw, in your code, you can take out the if, printing the boolean works – Quintec – 2019-03-25T21:00:58.020

1Need the 2 outputs be consistent or will any truthy/falsey values suffice? – Shaggy – 2019-03-25T21:32:08.840

1Some potential extra test cases, to clarify: Flowers flourish, from France, Flowers flourish ,from France, Flowers flourish from France., Flowers flourish from France ., .Flowers flourish from France, Flo.wers flourish fr,om France – trichoplax – 2019-03-25T21:32:51.733

With no definition of a sentence structure this is unclear. Is ", ," a valid input? Is ",This tolerable" or " This tolerable"? What about "This , ,tolerable, "? ...and what should they output? – Jonathan Allan – 2019-03-25T22:29:21.407

I'm surprised so many regulars answered rather than seeking clarity! – Jonathan Allan – 2019-03-25T22:35:51.643

1@JonathanAllan, it was pretty clear to me when originally posted that we should split on spaces and then check if the first character of every string was the same. – Shaggy – 2019-03-26T09:58:59.650

@Shaggy only because you made assumptions (I agree they were most likely correct, but as it stands they may not be). – Jonathan Allan – 2019-03-26T10:04:00.377

@JonathanAllan I answered based on the logical definition of "given a sentence." This , ,tolerable, isn't a sentence, for example. – AdmBorkBork – 2019-03-26T12:24:27.700

@AdmBorkBork "may contain" does not specify this and could allow perfectly normal (English?) sentences to be edited to less normal ones. Regardless, this is not a fruitful discussion; I already said "most likely correct", but I cannot make it so; that is the OPs prerogative. – Jonathan Allan – 2019-03-26T12:44:41.733

Answers

7

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.

Magic Octopus Urn

Posted 2019-03-25T19:23:45.177

Reputation: 19 422

4

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.

TFeld

Posted 2019-03-25T19:23:45.177

Reputation: 19 246

3

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.

AdmBorkBork

Posted 2019-03-25T19:23:45.177

Reputation: 41 581

41 bytes – mazzy – 2019-03-26T05:43:10.570

35 bytes with regexp – mazzy – 2019-03-26T08:01:09.833

1

@mazzy fixed trying to understand the intention

– Nahuel Fouilleul – 2019-03-26T08:36:04.737

@mazzy I'll let you post the regex version when the question is reopened. It's different enough to warrant its own answer. – AdmBorkBork – 2019-03-26T12:29:36.290

I'm agree. but this question is put on hold, so I can't create a new answer. – mazzy – 2019-03-26T15:27:50.457

3

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.

Carcigenicate

Posted 2019-03-25T19:23:45.177

Reputation: 3 295

Here's my Racket solution: (define(f s)(apply char=?(map(λ(x)(char-upcase(car(string->list x))))(string-split s)))) – Galen Ivanov – 2019-03-26T07:18:24.260

Much shorter in PicoLisp: (de f(s)(apply =(mapcar car(split(chop(lowc s))" ")))) – Galen Ivanov – 2019-03-26T07:47:33.587

2

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!

Jonathan Frech

Posted 2019-03-25T19:23:45.177

Reputation: 6 681

@nimi Thank you. – Jonathan Frech – 2019-03-25T23:15:39.130

2

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

Riley

Posted 2019-03-25T19:23:45.177

Reputation: 11 345

2

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

Nahuel Fouilleul

Posted 2019-03-25T19:23:45.177

Reputation: 5 582

what about punctuations? what about spaces or punctuations at the strart of string? – mazzy – 2019-03-26T07:49:25.557

this answer works for the given test cases, could be improved depending the requirements could be $_=!/^\W*+(.).*(?=\b\w)(?!\1)/i – Nahuel Fouilleul – 2019-03-26T08:06:51.430

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 – Nahuel Fouilleul – 2019-03-26T08:14:43.350

2

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.

Unrelated String

Posted 2019-03-25T19:23:45.177

Reputation: 5 300

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... – Unrelated String – 2019-03-25T22:13:14.680

1

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.

Arnauld

Posted 2019-03-25T19:23:45.177

Reputation: 111 334

or in one regex or with a space instead of \W

– Nahuel Fouilleul – 2019-03-25T20:35:47.130

@NahuelFouilleul, using test saves another byte. – Shaggy – 2019-03-25T20:45:50.487

1@NahuelFouilleul You should probably post is separately. – Arnauld – 2019-03-25T20:55:38.753

already posted the perl version, i don't master as well javascript, i'm happy to give you a hint – Nahuel Fouilleul – 2019-03-25T21:08:41.387

1

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

Shaggy

Posted 2019-03-25T19:23:45.177

Reputation: 24 623

1

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!

Embodiment of Ignorance

Posted 2019-03-25T19:23:45.177

Reputation: 7 014

1

Perl 6, 19 bytes

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

Try it online!

nwellnhof

Posted 2019-03-25T19:23:45.177

Reputation: 10 037

1

Java, (36 bytes)

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

TIO

Nahuel Fouilleul

Posted 2019-03-25T19:23:45.177

Reputation: 5 582

1

I think the input is allowed to start with a space, and this doesn't work for input like that.

– Sara J – 2019-03-25T22:13:28.847

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

– Nahuel Fouilleul – 2019-03-26T06:32:50.947

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 – Nahuel Fouilleul – 2019-03-26T10:19:32.280