20
\$\begingroup\$

Introduction

A pure word (or perfect word), as defined by me, is a word where the sum of the position in the alphabet of each letter in the word is perfectly divisible by the total length of the word. For example, abcb is a perfect word because 1 + 2 + 3 + 2 = 8, and 8 / 4 = 2.

Your task

Given a word as input, output whether or not it is a perfect word. The word may always be assumed to be lowercase.

Scoring

This is code-golf, so shortest program in bytes wins.

Examples

abcb: truthy
ccc: truthy
aaa: truthy
pure: truthy
word: truthy
bed: falsy
code: falsy
bode: falsy
\$\endgroup\$
7
  • \$\begingroup\$ What type of outputs are allowed? For example, 0 for truthy and a non-consistent nonzero number for falsy? Any two values? Truthy and falsy swapped? @All: you may want to vote here \$\endgroup\$
    – Luis Mendo
    Jan 15 at 11:21
  • \$\begingroup\$ @LuisMendo check the related meta post \$\endgroup\$
    – Ginger
    Jan 15 at 17:18
  • 2
    \$\begingroup\$ I know what "truthy" and "falsy" mean. I'm asking if the outputs can be non-consistent values (i.e. more than two values), or for example two distinct truthy values. You need to specify the output options allowed by the challenge. Voting to close as unclear until resolved \$\endgroup\$
    – Luis Mendo
    Jan 15 at 17:33
  • \$\begingroup\$ I'm pretty sure our consensus is that there is no default for decision problem output. E.g., is false for a perfect number and true for a non-perfect one allowed? What about 1 for a perfect number and any other number otherwise, or positive for perfect and negative for non-perfect? \$\endgroup\$ Jan 15 at 18:00
  • 6
    \$\begingroup\$ @taRadvylfsriksushilani The consensus appears not to be. However I would really like it if something as basic as output specifications were put in the challenge itself instead of hidden away somewhere on meta. It's not very beginner friendly seeing as experienced users don't seem to always recall the exact state of the meta. \$\endgroup\$
    – Wheat Wizard
    Jan 15 at 20:23

42 Answers 42

17
\$\begingroup\$

Factor, 37 16 bytes

[ mean fixnum? ]

Try it online!

Is the mean of the input an integer?

Why does this work?

Four reasons.

  • Strings in Factor are just sequences of code points.
  • Because the question is asking for a sum divided by a length. Otherwise known as the mean.
  • The mean word returns a ratio, not a float. In Factor, ratios automatically reduce to simplified form, which can be an integer. We can check for divisibility after taking the mean by checking whether the result is an integer or a ratio.
  • It doesn't matter whether the input ranges from 1-26 or 97-122. It doesn't change whether the mean is an integer or not.
\$\endgroup\$
13
\$\begingroup\$

Python 3, 33 bytes

lambda s:sum(map(ord,s))%len(s)<1

Try it online!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ wow i feel dumb now after reading this \$\endgroup\$
    – DialFrost
    Jan 16 at 3:08
12
\$\begingroup\$

R, 42 39 33 bytes

function(w)!mean(utf8ToInt(w))%%1

Try it online!

-6 bytes thanks to m90.

\$\endgroup\$
5
  • \$\begingroup\$ I think it's generally accepted to take string input as a vector of char codes. \$\endgroup\$
    – pajonk
    Jan 14 at 19:57
  • \$\begingroup\$ @pajonk ehh, that's always been a bit of a gray area to me, R has a perfectly good string type so I prefer to take input that way. \$\endgroup\$
    – Giuseppe
    Jan 14 at 20:15
  • \$\begingroup\$ Ok, I respect that. Also, the default for decision-problem is that truthy/falsy may be swapped for -1 (but that also feels like a design choice more than golf). \$\endgroup\$
    – pajonk
    Jan 14 at 20:52
  • 3
    \$\begingroup\$ Improvement: change sum to mean and the modulus to 1. \$\endgroup\$
    – m90
    Jan 15 at 8:59
  • \$\begingroup\$ use the new syntax: \(w)!mean(utf8ToInt(w))%%1 \$\endgroup\$ Jan 17 at 15:30
10
\$\begingroup\$

Jelly, 5 bytes

OSḍ@L

Try It Online!

OSḍ@L    Main Link
O        ord (vectorizes)
 S       sum
  ḍ@     is this divisible by
    L    the length of the input?

If outputting inconsistent truthy/falsy values is allowed:

Jelly, 4 bytes

OSọL

Try It Online!

OSọL    Main Link
O       ord (vectorizes)
 S      sum
  ọ     how many times is this divisible by
   L    the length?

This works using an observation made by caird coinheringaahing in chat that you do not need to account for the offset between A = 1 and A = 65 when you take the codepoint, since the codepoint offset will be added len(X) times and not affect the modulo.

Yes, caird also just straight up gave the algorithm, but to be fair, the observation was the only non-trivial part about this solution anyway.

\$\endgroup\$
0
10
\$\begingroup\$

05AB1E, 4 bytes

OIgÖ

Try it online! Takes input as a list of codepoints.

\$\endgroup\$
1
  • 8
    \$\begingroup\$ It would be more impressive to 'tie' Jelly, Husk and Vyxal-K if the input format was the same: each of those others takes a string as input, rather than already converted to a list of codepoints. Note that hyper-neutrino's Jelly answer would only be 3 bytes (SọL) if the input was already converted to codepoints... \$\endgroup\$ Jan 15 at 22:14
7
\$\begingroup\$

Vyxal, 5 bytes

C∑$LḊ

Try It Online!

Same thing as my Jelly solution.

C∑$LḊ    Full Program
C        ord (vectorizes)
 ∑       sum
  $      swap; bring the string back to the top
   L     length
    Ḋ    is the ord sum divisible by the length?
\$\endgroup\$
0
7
\$\begingroup\$

JavaScript (ES6), 58 bytes

w=>!([...w].reduce((s,c)=>s+parseInt(c,36)-10,0)%w.length)
\$\endgroup\$
4
  • \$\begingroup\$ Doesn't ! have higher precedence than %? \$\endgroup\$
    – Neil
    Jan 14 at 19:53
  • \$\begingroup\$ @Neil Oh yeah...I added the ! last minute and didn't really think it through. \$\endgroup\$ Jan 14 at 20:04
  • 1
    \$\begingroup\$ 50 bytes: s=>[...s].map(_=>x+=s.charCodeAt(i++),x=i=0)|x%i<1. Using map is kind of wasteful here, it seems like there should be a better way. \$\endgroup\$ Jan 14 at 22:31
  • 2
    \$\begingroup\$ -10 is not necessary \$\endgroup\$
    – tsh
    Jan 16 at 3:59
7
\$\begingroup\$

Haskell, 36 bytes

f w=sum(fromEnum<$>w)`mod`length w<1

Try it online!

\$\endgroup\$
7
\$\begingroup\$

Vyxal 2.4.1 K, 4 3 bytes

ṁ1Ḋ

Try it Online!

Ah yes classic pre-2.6 jank ftw. -1 thanks to Dominic

Explained

ṁ1Ḋ
      # First, the input is converted to a list of corresponding ordinal values by the `K`(eg mode) flag:
ṁ     #   push the arithmetic mean of that list
 1Ḋ   #   is that divisible by 1? (i.e is it a whole number)
\$\endgroup\$
1
6
\$\begingroup\$

Excel, 59 54 bytes

Saved 5 bytes thanks to pajonk.

=MOD(SUM(CODE(MID(A1,SEQUENCE(LEN(A1)),1))),LEN(A1))=0

Input is in cell A1. Output is wherever the formula is.

  • SEQUENCE(LEN(A1)) creates an array with values 1 to the word length.
  • MID(A1,SEQUENCE(~),1) pulls out each letter from the input one at a time.
  • CODE(MID(~)) finds the ASCII code for each letter. We don't have to convert this to 1-26 because it's 1 extra 96 for ever letter of the input so divisibility will be the same.
  • SUM(CODE(~)) adds all those values.
  • MOD(SUM(~),LEN(A1)) returns 0 if it's a whole number and a decimal if it isn't. If anything, this is the opposite of what we want because 0 is falsey and other numbers are truthy, at least in Excel.
  • MOD(~)=0 returns TRUE or FALSE.

Result

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I think you may omit the -96 as it's repeated LEN(A1) times in the sum and doesn't affect divisibility. Also, I don't have excel near me to check, but shouldn't simply passing LEN(A1) to the second argument of MOD work? \$\endgroup\$
    – pajonk
    Jan 14 at 21:04
  • \$\begingroup\$ @pajonk Spot on. Thanks. \$\endgroup\$ Jan 14 at 21:42
6
\$\begingroup\$

JavaScript (Node.js), 37 bytes

s=>eval(Buffer(s).join`+`)%s.length<1

Try it online!

\$\endgroup\$
6
\$\begingroup\$

Python, 24 bytes

lambda s:sum(s)%len(s)<1

Attempt This Online!

Takes input as a byte string. We don't need to subtract 95 from each element, because the sum will end up having 95 * length added on, which has no effect on the result modulo length.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ best python code pxeger! \$\endgroup\$
    – DialFrost
    Jan 16 at 3:09
6
\$\begingroup\$

brainfuck, 162 bytes

>+[+[>+<+<]>]+[,[>[>+<<->-]<[>>>+<<<-]>>>>+<<[<+>-]<<+>>]<<]>>>[-]>>[<+>-]<[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>[-]+++++++>[-]<[>+++++++<-]>>[<.[-]>[-]>[-]]<[-.[-]]

Try It Online!

outputs 0 for truthy and 1 for falsey

This one was a lot of fun. Not necessary golf-optimal but hey, brainfuck solution :)

Explanation

; 96 algorithm from esolangs constants
; initialise tape to (1)/96/0/0/0
>+[+[>+<+<]>]+[
    ; while(getchar())
    ,[>
        [>+<<->-]
        <[>>>+<<<-]>>>>+<<[<+>-]<<+>>
        ; 0/96/(0)/cumulative/length
    ]
    <<
]

; divmod algorithm from esolangs
>>>[-]>>[<+>-]
<[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]

; prepare 0 for output
>[-]+++++++>[-]<[>+++++++<-]

; if(sum%length){print 1}else{print 0}
>>[<.[-]>[-]>[-]]<[-.[-]]
\$\endgroup\$
5
\$\begingroup\$

Julia 1.0, 25 bytes

!x=sum(Int,x)%length(x)<1

Try it online!

\$\endgroup\$
5
\$\begingroup\$

APL+WIN, 22 16 bytes

Prompts for string

0=(⍴s)|+/⎕av⍳s←⎕

Try it online!Thanks to Dyalog Classic

\$\endgroup\$
5
\$\begingroup\$

Husk, 5 4 bytes

Edit: -1 byte thanks to Razetime

¦L¹Σ

Try it online!

Outputs truthy (non-zero) for perfect words, falsy (zero) for non-perfect words.

\$\endgroup\$
2
  • \$\begingroup\$ sum works on strings: Try it online! \$\endgroup\$
    – Razetime
    Jan 15 at 10:50
  • \$\begingroup\$ @Razetime - Aha! Thankyou very much! \$\endgroup\$ Jan 15 at 10:53
5
\$\begingroup\$

Wolfram Mathematica, 34 24 bytes

1∣Mean@LetterNumber@#&

-10 bytes from @att

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This isn't reusable, since z will already be defined on subsequent calls. Input also needs to be taken as a list of characters in order to correctly handle length-1 strings (Mathematica treats them as characters). 24 bytes \$\endgroup\$
    – att
    Jan 18 at 22:07
4
\$\begingroup\$

Japt, 6 bytes

Takes input as an array of characters. The c can be removed by instead taking input as an array of codepoints.

xc vUl

Try it

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

Ly, 8 bytes

iys&+l%!

Try it online!

i         - read STDIN onto stack as codepoints
 ys       - push length of the stack, save to backup cell
   &+     - sum the codepoints on the stack (1)
     l    - load the number of chars from the backup cell
      %   - module math to push "0" if evenly divisble, ">0" otherwise
       !  - negate modulo result so that 0->1 and other->0

(1) The code includes the length of the original stack in the sum of the codepoints to save the p byte that would be needed to delete it. But it doesn't change the result of the modulo math to get the final result.

When the code exits, the only thing on the stack is the 0|1 result, which is printed as a number automatically.

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

Java, 31 bytes

s->s.chars().sum()%s.length()<1

Try it online!

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

BQN, 16 12 9 8 bytes

Edit: -3 bytes thanks to ovs, and -1 byte thanks to DLosc

≠|·+´@-⊢

Try it at BQN online REPL

Outputs nonzero (truthy) for non-perfect words, zero (falsy) for perfect words.

\$\endgroup\$
3
  • \$\begingroup\$ You can use @ instead of 'a' and the ¨ is not necessary. \$\endgroup\$
    – ovs
    Jan 16 at 22:01
  • \$\begingroup\$ @ovs - Thanks a lot! And: I must be slowly starting to understnad BQN, because I think I could actually understand both of those golfs right away... \$\endgroup\$ Jan 16 at 23:02
  • \$\begingroup\$ Turns out the ˜ is not necessary either: without it, the sum-and-mod is applied to a bunch of negative numbers instead of positive numbers, which produces the same results vis-a-vis zero vs non-zero. \$\endgroup\$
    – DLosc
    Jan 28 at 17:25
3
\$\begingroup\$

Charcoal, 9 bytes

¬﹪ΣEθ℅ιLθ

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for a perfect word, nothing if not. Explanation:

    θ        Input string
   E         Map over characters
      ι      Current character
     ℅       Ordinal
  Σ          Sum
¬﹪           Is divisible by
        θ    Input string
       L     Length
             Implicitly print
\$\endgroup\$
3
\$\begingroup\$

SNOBOL4 (CSNOBOL4), 103 98 bytes

	L =SIZE(W =INPUT)
N	W LEN(1) . X REM . W :F(O)
	S =S + ORD(X)	:(N)
O	OUTPUT =1	EQ(REMDR(S,L))
END

Try it online!

Prints 1 for truthy and nothing for falsey.

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

J, 15 bytes

0=#|1#.96-~3&u:

Try it online!

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

Retina 0.8.2, 46 bytes

.
$&26$*
+T`1l`_3l`\D.
^
2
O^`.
3
1
^(1+)2\1*$

Try it online! Link includes test cases. Explanation:

.
$&26$*

Append 26 1s to each letter.

+T`1l`_3l`\D.

Cycle the letters through the alphabet, removing a 1 each time. Once the letter reaches a, replace it with a 3. (Note that this numbers the alphabet in reverse but this doesn't affect the divisibility check.)

^
2
O^`.

Insert a 2 and then sort the digits in reverse order, so you have the 3s for each letter, the 2, and then the 1s representing the sum of the positions.

3
1

Change the 3s into 1s.

^(1+)2\1*$

Check that the leading 1s divide the trailing 1s.

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

Vyxal , 11 10 bytes

-1 thanks to Neil

ƛkanḟ;∑?LḊ

Try it Online!

Explanation

ƛkanḟ;∑?LḊ
ƛ            Start a mapping lambda for input
 ka          Lowercase alphabet
   n         Current letter
    ḟ        Find letter in the alphabet, return index
     ;       Close mapping lambda
      ∑      Sum the list of indices.
       ?L    Get Length of input
         Ḋ   Check if Sum is divisible by the length.
\$\endgroup\$
2
  • \$\begingroup\$ probably can be golfed a lot \$\endgroup\$
    – mathcat
    Jan 14 at 19:43
  • \$\begingroup\$ You don't need to increment because all that does is increase the sum by the length, which doesn't change its divisibility. \$\endgroup\$
    – Neil
    Jan 14 at 19:55
3
\$\begingroup\$

Scala, 17 bytes

s=>s.sum%s.size<1

Try it online!

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

Python 3, 50 bytes

s=input();print(sum(ord(c)-95for c in s)%len(s)<1)

Try it online!

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

K (ngn/k), 14 11 bytes

-3 bytes from @Dominic van Essen's improvement

{~(#x)!+/x}

Try it online!

  • +/x take the sum of the ASCII codes of the (strictly lowercase) input
  • (#x)! mod this sum by the length of the input
  • ~ "not" the result, i.e. return 1 if the sum is evenly divisible by the length (i.e. the mod returns 0), and 0 otherwise
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Can you leave-out the 48! for 11 bytes...? \$\endgroup\$ Jan 15 at 22:34
  • \$\begingroup\$ Good catch, thanks! \$\endgroup\$
    – coltim
    Jan 16 at 20:45
3
\$\begingroup\$

Python, 125 bytes

Wow I feel like an idiot after reading all these other amazing answers.

j=[ord(k)-96 for k in str(input(""))]
l=len(j)
while len(j)>1:j[0]+=j[1];del j[1]
print("%sy"%("truth"if j[0]%l<1else"fals"))

I think how this works is pretty trivial.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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