Chunky vs. Smooth Strings

29

3

Consider a string of length N, such as Peanut Butter with N = 13. Notice that there are N-1 pairs of neighboring characters in the string. For Peanut Butter, the first of the 12 pairs is Pe, the second is ea, the last is er.

When the pairs are mostly different characters, the string has a chunky quality, e.g. chUnky.
When these pairs are mostly the same character, the string has a smooth quality, e.g. sssmmsss.

Define the chunkiness of a string to be the ratio of the number of pairs with two different characters to the total number of pairs (N-1).

Define the smoothness of a string to be the ratio of the number of pairs with two identical characters to the total number of pairs (N-1).

For example, Peanut Butter only has one pair with identical characters (tt), so its smoothness is 1/12 or 0.0833 and its chunkiness is 11/12 or 0.9167.

Empty strings and strings with only one character are defined to be 100% smooth and 0% chunky.

Challenge

Write a program that takes in a string of arbitrary length and outputs either its chunkiness or smoothness ratio as a floating point value.

  • Take input via stdin or the command line, or you may write a function that takes a string.
  • You can assume the input string only contains printable ASCII characters (and hence is single-line).
  • Print the float to stdout to 4 or more decimal places, or you can choose to return it if you wrote a function. Decimal places that convey no information are not required, e.g. 0 is fine instead of 0.0000.
  • Choose chunkiness or smoothness as you prefer. Just be sure to say which one your program outputs.

The shortest code in bytes wins.

Examples

Peanut Butter → Chunkiness: 0.91666666666, Smoothness: 0.08333333333
chUnky → Chunkiness: 1.0, Smoothness: 0.0
sssmmsss → Chunkiness: 0.28571428571, Smoothness: 0.71428571428
999 → Chunkiness: 0.0, Smoothness: 1.0
AA → Chunkiness: 0.0, Smoothness: 1.0
Aa → Chunkiness: 1.0, Smoothness: 0.0
! → Chunkiness: 0.0, Smoothness: 1.0
[empty string] → Chunkiness: 0.0, Smoothness: 1.0

Bonus question: Which do you prefer, chunky or smooth strings?

Calvin's Hobbies

Posted 2015-07-14T02:40:34.627

Reputation: 84 000

8-1 No overhanded tag. – Dennis – 2015-07-14T02:45:57.070

22+1 Conclusive proof that chunky peanut butter should be the default. – BrainSteel – 2015-07-14T03:25:03.030

Some languages have a hard time reading no input at all. Would it be admissible to assume that the input is newline-terminated? – Dennis – 2015-07-14T04:25:04.097

@Dennis Yes, that's fine. – Calvin's Hobbies – 2015-07-14T04:32:42.003

9@BrainSteel Chunky should only be the default if you're a computer; they like having chunks available. Peanut butter made for people should hide those implementation details, and be smooth as silk for the user. – Geobits – 2015-07-14T13:01:11.870

Hm.. with all the fully chunky chunkiness solutions, I wonder whether there are fully smooth smoothness solutions?

– ojdo – 2015-07-15T14:12:44.680

Will the input contain tabs? – kirbyfan64sos – 2015-07-30T02:00:11.033

@kirbyfan64sos Tabs aren't printable ASCII. So no. – Calvin's Hobbies – 2015-07-30T05:31:03.447

Answers

7

APL, 10 bytes

This reads input from stdin and prints the chunkiness to stdout. The algorithm is the same one used for the J solution.

(+/÷⍴)2≠/⍞

FUZxxl

Posted 2015-07-14T02:40:34.627

Reputation: 9 656

19

CJam, 19 bytes

q_1>_@.=:!1b\,d/4mO

100% chunky source code that calculates chunkiness.

Try this chunky goodness online.

How it works

q_                  e# Read from STDIN and push a copy.
  1>_               e# Discard the first character and push a copy.
     @              e# Rotate the original on top.
      .=            e# Vectorized comparison (1 if equal, 0 if not).
        :!          e# Mapped logical NOT (0 if equal, 1 if not).
          1b        e# Base 1 conversion (sum).
            \,      e# Swap with the shortened string and push its length.
              d/    e# Cast to double and divide.
                4mO e# Round to four decimal places.

Obviously, NaN rounded to 4 decimal places is 0.

Dennis

Posted 2015-07-14T02:40:34.627

Reputation: 196 637

1I don't think you need to round it to 4 digits. It says "4 or more", and trailing zeros are not needed. This is much more elegant than the 2ew approach I tried. The 0/1 letter special cases were killing me. – Reto Koradi – 2015-07-14T03:56:06.363

@RetoKoradi Rounding maps NaN to 0. I don't know a shorter way. – Dennis – 2015-07-14T03:58:56.063

Yes, while playing with it some more, I just noticed that you get a NaN for 1-character inputs. The short inputs are by far the most painful part with this one. BTW, the online link has slightly different code than the version you posted. One _ moved. Not sure if it matters. – Reto Koradi – 2015-07-14T04:02:55.740

@RetoKoradi Sure does. The linked code wan't 100% chunky. :P – Dennis – 2015-07-14T04:03:55.297

Curious that CJam doesn't have an equivalent of GS's or. – Peter Taylor – 2015-07-14T06:31:52.663

@PeterTaylor: It does, but 1e| is just as long as 4mO and I thought rounding NaN to 4 decimal places was more interesting. – Dennis – 2015-07-14T06:34:48.053

Oh, is that what "logical or" means? I thought about it a bit more, and concluded that _1? was probably the intended idiom. – Peter Taylor – 2015-07-14T07:10:48.717

-1, jam is never chunky. – Alex A. – 2015-07-14T14:42:01.373

3@AlexA. Jam with fruit chunks is at least 10% chunky. – Dennis – 2015-07-14T14:53:30.500

@Dennis Fair point. +1. – Alex A. – 2015-07-14T15:03:30.713

13

Pyth, 13 12 bytes

csJnVztz|lJ1

Fully chunky code calculating chunkiness.

Demonstration. Test harness.

csJnVztz|lJ1
                 Implicit: z = input()
   nV            n, !=, vectorized over
     z           z
      tz         z[:-1]
                 V implitly truncates.
  J              Store it in J.
 s               sum J
c                floating point divided by
         |       logical or
          lJ     len(J)
            1    1

isaacg

Posted 2015-07-14T02:40:34.627

Reputation: 39 268

In the online version, I get an error when I leave the input empty. So as far as I can tell, it fails the last test case. – Reto Koradi – 2015-07-14T08:06:50.587

@RetoKoradi That's weird - it works fine in the offline version. It's probably a bug with the online website. – isaacg – 2015-07-14T08:10:30.760

@RetoKoradi Confirmed - the very use of z cause an error on the empty input online. I'll go and fix that bug. This code is fine, however. – isaacg – 2015-07-14T08:12:36.253

It works if I hit return once in the input box. But other strings do not need a return at the end. With nothing typed in the input box, it seems to get no input at all, and your code blows up when it tries to use the input. – Reto Koradi – 2015-07-14T08:15:35.167

@RetoKoradi Thanks. I think I know the problem, shouldn't be hard to fix. – isaacg – 2015-07-14T08:17:21.333

Just out of curiosity: What does the "2 character substrings" operator in Pyth do if the string is less than 2 characters? Produce an empty list? That would make sense to me. In CJam it fires an exception, which is very inconvenient when trying to use it for this problem. – Reto Koradi – 2015-07-14T08:20:28.840

Let us continue this discussion in chat.

– isaacg – 2015-07-14T08:21:09.973

8

TI-BASIC, 46 bytes

Input Str1
If 2≤length(Str1
mean(seq(sub(Str1,X,1)=sub(Str1,X-1,1),X,2,length(Str1
Ans

sub(x1,x2,x3 gives the substring of string x1 starting (one-based) at number x2 and ending at number x3, then seq( builds a sequence.

Gives the smoothness value. The Ans variable is 0 by default, so we don't need an Else to the If statement, or to store anything to Ans beforehand.

lirtosiast

Posted 2015-07-14T02:40:34.627

Reputation: 20 331

7

Matlab (37 36 bytes)

This can be done with the following anonymous function, which returns chunkiness:

f=@(x)nnz(diff(x))/max(numel(x)-1,1)

Comments:

  • In old Matlab versions (such as R2010b) you need + to cast the char array x to a double array:

    f=@(x)nnz(diff(+x))/max(numel(x)-1,1)`
    

    But that's not the case in recent versions (tested in R2014b), which saves one byte. Thanks to Jonas for his comment.

  • The expression with max handles the one-character and zero-character cases (for chunkiness)

Example:

>> f=@(x)nnz(diff(x))/max(numel(x)-1,1)
f = 
    @(x)nnz(diff(x))/max(numel(x)-1,1)

>> f('Peanut Butter')
ans =
   0.9167

Luis Mendo

Posted 2015-07-14T02:40:34.627

Reputation: 87 464

On R2014b, diff('abc') will not produce a warning. – Jonas – 2015-07-14T08:52:53.503

6

><>, 40 36 bytes

00ii:0(?v:@=1$-{+{1+}}20.
~:0=+,n;>~

This program returns the chunkiness of a string.

Explanation

00i         Push 0 (# unequal pairs), 0 (length of string - 1) and read first char

[main loop]

i           Read a char
:0(?v       If we've hit EOF, go down a row
:@=1$-      Check (new char != previous char)
{+          Add to unequal pairs count
{1+         Increment length by 1
}}20.       Continue loop

[output]

~~          Pop last two chars (top one will be -1 for EOF)
:0=+        Add 1 to length if zero (to prevent division by zero errors)
,           Divide, giving chunkiness
n;          Output and halt

Previous submission (37 + 3 = 40 bytes)

l1)?v1n;
n,$&\l1-}0& \;
l2(?^$:@=&+&>

This program returns the smoothness of a string. Input is via the -s flag, e.g.

py -3 fish.py chunkiness.fish -s "Peanut Butter"

Sp3000

Posted 2015-07-14T02:40:34.627

Reputation: 58 729

6

C#, 94 89 bytes

Sub 100 bytes, so I guess that's some form of victory in itself?

This is a function definition (allowed as per the spec) which returns the smoothness of the input string:

Func<string,float>(s=>s.Length>1?s.Zip(s.Skip(1),(a,b)=>a==b?1f:0).Sum()/(s.Length-1):1);

Pretty straightforward, if the length is 0 or 1 it returns 1, otherwise it compares the string to itself less the first character, then returns the number of identical pairs divided by the number of pairs.

Edit - replaced Substring with Skip. Rookie mistake!

Sok

Posted 2015-07-14T02:40:34.627

Reputation: 5 592

5

J, 14 13 bytes

Computes the chunkiness. Kudos to J for defining 0 % 0 to be equal to 0.

(]+/%#)2~:/\]

Try it online

Here is an explanation:

   NB. sample input
   in =. 'sssmmsss'

   NB. all infixes of length 2
   2 ]\ in
ss
ss
sm
mm
ms
ss
ss

    NB. are the parts of the infix different?
    2 ~:/\ in
0 0 1 0 1 0 0

    NB. sum and item count of the previous result
    (+/ , #) 2 ~:/\ in
2 7

    NB. arithmetic mean: chunkiness
    (+/ % #) 2 ~:/\ in
0.285714

    NB. as a tacit verb
    (] +/ % #) 2 ~:/\ ]

    NB. 0 divided by 0 is 0 in J
    0 % 0
0

FUZxxl

Posted 2015-07-14T02:40:34.627

Reputation: 9 656

(]+/%#)2~:/\] saves 1 byte. – FrownyFrog – 2018-04-26T06:18:49.330

@FrownyFrog Cool! How could I miss this? – FUZxxl – 2018-04-26T07:36:58.840

Could you add a TIO-link with test code?

– Kevin Cruijssen – 2018-04-26T10:00:46.260

4

CJam, 23 bytes

q_,Y<SS+@?2ew_::=:+\,d/

Explanation:

q                           e# read input
 _,                         e# its length
   Y<                       e# is less than 2?
     SS+                    e# then a smooth string
        @?                  e# otherwise the input
          2ew               e# pairs of consecutive characters
             _::=           e# map to 1 if equal, 0 if not
                 :+         e# sum (number of equal pairs)
                   \,       e# total number of pairs
                     d/     e# divide

This outputs the smoothness ratio.

Ypnypn

Posted 2015-07-14T02:40:34.627

Reputation: 10 485

4

CJam, 16 bytes

1q2ew::=_:+\,d/*

Cheaty source code that calculates smoothness.

For inputs of length 0 or 1, this prints the correct result before exiting with an error. With the Java interpreter, error output goes to STDERR (as it should).

If you try the code online, just ignore everything but the last line of output.

How it works

1q               e# Push a 1 and read from STDIN.
  2ew            e# Push the overlapping slices of length 2.
                 e# This will throw an error for strings of length 0 or 1,
                 e# so the stack (1) is printed and the program finishes.
     ::=         e# Twofold vectorized comparision.
        _:+      e# Push a copy and add the Booleans.
           \,    e# Swap with the original and compute its length.
             d/  e# Cast to double and divide.
               * e# Multiply with the 1 on the bottom of the stack.

Dennis

Posted 2015-07-14T02:40:34.627

Reputation: 196 637

3

Nim, 105 96 91 bytes

proc f(s):any=
 var a=0;for i,c in s[.. ^2]:a+=int(s[i+1]!=c)
 a.float/max(s.len-1,1).float

Trying to learn Nim. This calculates the chunkiness of a string.

(If I try to read this as Python the indentation looks all messed up... Now it looks more like Ruby...)

Sp3000

Posted 2015-07-14T02:40:34.627

Reputation: 58 729

3

Julia, 52 bytes

Smoothness!

s->(n=length(s))<2?1:mean([s[i]==s[i+1]for i=1:n-1])

This creates an unnamed function that accepts a string and returns a numeric value.

If the length of the input is less than 2, the smoothness is 1, otherwise we calculate the proportion of identical adjacent characters by taking the mean of an array of logicals.

Alex A.

Posted 2015-07-14T02:40:34.627

Reputation: 23 761

3

Python 3, 63 Bytes

This is an anonymous lambda function which takes a string as the argument, and returns it's chunkiness.

lambda n:~-len(n)and sum(x!=y for x,y in zip(n,n[1:]))/~-len(n)

To use it, give it a name and call it.

f=lambda n:~-len(n)and sum(x!=y for x,y in zip(n,n[1:]))/~-len(n)
f("Peanut Butter") -> 0.08333333333333333
f("!")             -> 0
f("")              -> -0.0

Kade

Posted 2015-07-14T02:40:34.627

Reputation: 7 463

Instead of the anonymous function, you can use: def f(n):, which has exactly the same number of characters as lambda n:. This removes the need to name your function. – Tristan Reid – 2015-07-15T18:02:42.497

@TristanReid def f(n): also needs a return – Sp3000 – 2015-07-16T07:27:33.360

Oops! Good catch - I'm new to codegolf, I should assume more thought has gone into this and test locally. Apologies! – Tristan Reid – 2015-07-16T23:20:37.810

3

Python 3, 52 bytes

lambda s:sum(map(str.__ne__,s,s[1:]))/(len(s)-1or 1)

This calculates chunkiness, and outputs -0.0 for the empty string. If don't like negative zeroes you can always fix that with an extra byte:

lambda s:sum(map(str.__ne__,s,s[1:]))/max(len(s)-1,1)

Sp3000

Posted 2015-07-14T02:40:34.627

Reputation: 58 729

2

Haskell, 64 bytes

f[]=1
f[_]=1
f x=sum[1|(a,b)<-zip=<<tail$x,a==b]/(sum(x>>[1])-1)

Outputs smoothness. e.g. f "Peanut Butter" -> 8.333333333333333e-2.

How it works:

f[]=1                               -- special case: empty list
f[_]=1                              -- special case: one element list

f x=                                -- x has at least two elements
         (a,b)<-zip=<<tail$x        -- for every pair (a,b), drawn from zipping x with the tail of itself
                            ,a==b   -- where a equals b
      [1|                        ]  -- take a 1
   sum                              -- and sum it
              /                     -- divide  by
                   (x>>[1])         -- map each element of x to 1
               sum                  -- sum it
                           -1       -- and subtract 1

sum(x>>[1]) is the length of x, but because Haskell's strong type system requires to feed fractionals to /, I can't use length which returns integers. Converting integers to fractionals via fromInteger$length x is far too long.

nimi

Posted 2015-07-14T02:40:34.627

Reputation: 34 639

Did you try working with Rationals?

– recursion.ninja – 2015-07-14T19:27:32.650

@recursion.ninja: no, I didn't because I think a 18 byte import Data.Ratio is too expensive. – nimi – 2015-07-15T15:16:18.683

2

JavaScript (ES6), 55 bytes

Smoothness, 56 bytes

f=x=>(z=x.match(/(.)(?=\1)/g))?z.length/--x.length:+!x[1]

Chunkiness, 55 bytes

f=x=>(z=x.match(/(.)(?!\1)/g))&&--z.length/--x.length||0

Demo

Calculates smoothness, as that is what I prefer. Only works in Firefox for now, as it is ES6.

f=x=>(z=x.match(/(.)(?=\1)/g))?z.length/--x.length:+!x[1]

O.innerHTML += f('Peanut Butter') + '\n';
O.innerHTML += f('chUnky') + '\n';
O.innerHTML += f('sssmmsss') + '\n';
O.innerHTML += f('999') + '\n';
O.innerHTML += f('AA') + '\n';
O.innerHTML += f('Aa') + '\n';
O.innerHTML += f('!') + '\n';
O.innerHTML += f('') + '\n';
<pre id=O></pre>

rink.attendant.6

Posted 2015-07-14T02:40:34.627

Reputation: 2 776

2

Ruby, 69 66 bytes

->s{(c=s.chars.each_cons(2).count{|x,y|x!=y}.to_f/~-s.size)>0?c:0}

Try it online!

Shaved of a few bytes with comments from IMP. Also, with the upcoming version 2.7.0 of Ruby it's possible to save some bytes by replacing |x,y|x!=y with @1!=@2

daniero

Posted 2015-07-14T02:40:34.627

Reputation: 17 193

if you move the .to_f/~-s.size into the assignment of c, then you can shave a byte off with the ternary operation: f=->s{(c=s.chars.each_cons(2).count{|x,y|x!=y}.to_f/~-s.size)>0?c:0} – IMP1 – 2019-07-25T09:39:03.117

Also, do you need the f=? I'm not 100% on the rules about that. The challenge says you can return a function that takes a string, which a stabby lambda is. – IMP1 – 2019-07-25T09:40:20.347

also, while the Perl answer might be the same length, it's not got that 100% chunkiness that this answer does. – IMP1 – 2019-07-25T09:43:11.283

@IMP1 Thanks :) – daniero – 2019-07-27T13:32:46.313

2

KDB(Q), 30

Returns smoothness.

{1^sum[x]%count x:1_(=':)(),x}

Explanation

                         (),x    / ensure input is always list
                x:1_(=':)        / check equalness to prev char and reassign to x
   sum[x]%count                  / sum equalness divide by count N-1
 1^                              / fill null with 1 since empty/single char will result in null
{                             }  / lamdba

Test

q){1^sum[x]%count x}1_(=':)(),x}"Peanut Butter"
0.08333333
q){1^sum[x]%count x:1_(=':)(),x}"sssmmsss"
0.7142857
q){1^sum[x]%count x:1_(=':)(),x}"Aa"
0f
q){1^sum[x]%count x:1_(=':)(),x}"aa"
1f
q){1^sum[x]%count x:1_(=':)(),x}"chUnky"
0f
q){1^sum[x]%count x:1_(=':)(),x}"!"
1f
q){1^sum[x]%count x:1_(=':)(),x}""
1f

WooiKent Lee

Posted 2015-07-14T02:40:34.627

Reputation: 413

1

Java 8, 84 82 bytes

s->{float l=s.length()-1,S=s.split("(.)(?=\\1)").length-1;return l<1?1:S<1?0:S/l;}

Outputs Smoothness.

Try it online.

Explanation:

s->{                     // Method with String parameter and float return-type
  float l=s.length()-1,  //  Length of the input-String minus 1 (amount of pairs in total)
        S=s.split("(.)(?=\\1)").length-1;
                         //  Length of the input split by duplicated pairs (with lookahead)
  return l<1?            //  If the length of the input is either 0 or 1:
          1              //   Return 1
         :S<1?           //  Else-if `S` is -1 or 0:
          0              //   Return 0
         :               //  Else:
          S/l;}          //   Return duplicated pairs divided by the length-1

Kevin Cruijssen

Posted 2015-07-14T02:40:34.627

Reputation: 67 575

1

Coconut, 38 bytes

s->sum(map((!=),s,s[1:]))/-~len(s[2:])

Try it online!

A Python 3 port would be 50 bytes.

ovs

Posted 2015-07-14T02:40:34.627

Reputation: 21 408

1

Python 3, 69 bytes

No one has posted a Python solution yet, so here's a fairly straightforward implementation of a "chunkiness" function. It short-circuits on a string of length 1, and prints 0 (which is an integer rather than a float but seems to be allowed according to the rules).

On an empty string, it outputs -0.0 rather than 0.0. Arguably this is could be considered acceptable, as -0.0 == 0 == 0.0 returns True.

def c(s):l=len(s)-1;return l and sum(s[i]!=s[i+1]for i in range(l))/l

Examples:

>>> c(''); c('a'); c('aaa'); c("Peanut Butter")
-0.0
0
0.0
0.916666666667
>>> -0.0 == 0 == 0.0
True

(Python 3 is used for its default float division.)

mathmandan

Posted 2015-07-14T02:40:34.627

Reputation: 943

1

C, 83 bytes

float f(char*s){int a=0,b=0;if(*s)while(s[++a])b+=s[a]!=s[a-1];return--a?1.*b/a:b;}

A function returning chunkiness.

Explanation

float f(char *s) {

Accept a C string, and return a float (double would work but is more chars).

int a=0, b=0;

Counters - a for total pairs, b for non-matching pairs. Using int limits the "arbitrary length" of the string, but that's only a minor violation of the requirements and I'm not going to fix it.

if (*s)

Special case the empty string - leave both counters zero.

    while (s[++a])

Non-empty string - iterate through it with pre-increment (so first time through the loop, s[a] will be the second character. If the string has only one character, the loop body will not be entered, and a will be 1.

        b += s[a]!=s[a-1];

If the current character differs from the previous, increment b.

return --a ? 1.*b/a : b;
}

After the loop, there are three possibilities: 'a==0,b==0' for an empty input, 'a==1,b==0' for a single-character input or 'a>1,b>=0' for multi-character input. We subtract 1 from a (the ? operator is a sequence point, so we're safe), and if it's zero, we have the second case, so should return zero. Otherwise, b/a is what we want, but we must promote b to a floating-point type first or we'll get integer division. For an empty string, we'll end up with a negative zero, but the rules don't disallow that.

Tests:

#include <stdio.h>
int main(int argc, char **argv)
{
    while (*++argv)
        printf("%.6f %s\n", f(*argv), *argv);
}

Which gives:

./chunky 'Peanut Butter' chUnky sssmmsss 999 AA Aa '!' ''
0.916667 Peanut Butter
1.000000 chUnky
0.285714 sssmmsss
0.000000 999
0.000000 AA
1.000000 Aa
0.000000 !
-0.000000 

as required.

Toby Speight

Posted 2015-07-14T02:40:34.627

Reputation: 5 058

1

Ignore my previous deleted comment.. 80 bytes: a,b;float f(char*s){if(*s)for(a=b=0;s[++a];)b+=s[a]!=s[a-1];return--a?1.*b/a:b;}

– Kevin Cruijssen – 2018-04-26T10:10:05.437

66 bytes using compiler flag (if you're into that sort of thing). edit: and I switched it to gcc – vazt – 2018-04-27T17:08:48.640

1

Perl, 69

Function returning smoothness:

sub f{($_)=@_;$s=s/(.)(?!\1)//sgr;chop;!$_||length($s)/length;}

Explanation

sub f {
    # read argument into $_
    ($_) = @_;

    # copy $_ to $s, removing any char not followed by itself
    # /s to handle newlines as all other characters
    $s = s/(.)(?!\1)//sgr;

     # reduce length by one (unless empty)
    chop;

    # $_ is empty (false) if length was 0 or 1
    # return 1 in that case, else number of pairs / new length
    !$_ || length($s)/length;
}

Tests

printf "%.6f %s\n", f($a=$_), $a foreach (@ARGV);

0.083333 Peanut Butter
0.000000 chUnky
0.714286 sssmmsss
1.000000 999
1.000000 AA
0.000000 Aa
1.000000 !
1.000000 

Toby Speight

Posted 2015-07-14T02:40:34.627

Reputation: 5 058

1

Mathematica, 73 72 bytes

This doesn't win anything for size, but it's straightforward:

Smoothness

N@Count[Differences@#,_Plus]/(Length@#-1)&@StringSplit[#,""]&

In[177]:= N@Count[Differences@#,_Plus]/(Length@#-1)&@StringSplit[#,""] &@"sssmmsss"

Out[177]= 0.285714

rcollyer

Posted 2015-07-14T02:40:34.627

Reputation: 111

Length[#] -> Length@# saves a stroke. So does eliminating N@ and changing 1 to 1. – hYPotenuser – 2015-07-29T18:32:26.233

@hYPotenuser yep. missed it. – rcollyer – 2015-07-29T18:42:05.043

1

GeL: 76 73 characters

Smoothness.

@set{d;0}
?\P$1=@incr{d}
?=
\Z=@lua{c=@column -1\;return c<1and 1or $d/c}

Sample run:

bash-4.3$ for i in 'Peanut Butter' 'chUnky' 'sssmmsss' '999' 'AA' 'Aa' '!' ''; do
>     echo -n "$i -> "
>     echo -n "$i" | gel -f smooth.gel
>     echo
> done
Peanut Butter -> 0.083333333333333
chUnky -> 0
sssmmsss -> 0.71428571428571
999 -> 1
AA -> 1
Aa -> 0
! -> 1
 -> 1

(GeL = Gema + Lua bindings. Much better, but still far from winning.)

Gema: 123 120 characters

Smoothness.

@set{d;0}
?\P$1=@incr{d}
?=
\Z=@subst{\?\*=\?.\*;@cmpn{@column;1;10;10;@fill-right{00000;@div{$d0000;@sub{@column;1}}}}}

Sample run:

bash-4.3$ for i in 'Peanut Butter' 'chUnky' 'sssmmsss' '999' 'AA' 'Aa' '!' ''; do
>     echo -n "$i -> "
>     echo -n "$i" | gema -f smooth.gema
>     echo
> done
Peanut Butter -> 0.0833
chUnky -> 0.0000
sssmmsss -> 0.7142
999 -> 1.0000
AA -> 1.0000
Aa -> 0.0000
! -> 1.0
 -> 1.0

(Was more an exercise for myself to see what are the chances to solve it in a language without floating point number support and generally painful arithmetic support. The 2nd line, especially the \P sequence, is pure magic, the last line is real torture.)

manatwork

Posted 2015-07-14T02:40:34.627

Reputation: 17 865

0

Jelly, 7 4 bytes

=ƝÆm
 Ɲ   // For all pairs of neighbouring elements,
=    // return 1 if they're equal, 0 otherwise.
  Æm // Take the arithmetic mean of the resulting list.

Computes smoothness.
Cut off three bytes thanks to Dennis.

Try it online!

Nit

Posted 2015-07-14T02:40:34.627

Reputation: 2 667

0

Forth (gforth), 92 bytes

: f 1e dup 1 > if 1- dup s>f 0e 0 do dup i + dup 1+ c@ swap c@ = s>f f- loop fswap f/ then ;

Try it online!

Takes in a string (as the Forth standard combo of address and length) and returns the smoothness. Result is placed on the floating point stack

Explanation

1e                \ places 1 on the floating point stack, to use as a "default" value
dup 1 > if        \ duplicates the length of the string and checks if it's greater than 1
   1- dup s>f     \ subtract 1 from length and copy it to the floating point stack
   0e             \ places 0 on the floating point stack
   0 do           \ sets up a loop from 0 to length - 1
      dup i +     \ get the current character's address by adding index to string start
      dup 1+      \ copy address and add 1 to get the next character's address
      c@ swap c@  \ get the character at each of the addresses
      = s>f       \ compare the two characters and move to the floating point stack
      f-          \ subtract result from counter (true in Forth defaults to -1)
   loop           \ end the loop
   fswap f/       \ swap the counter and the total and divide to get result
then              \ end the loop

reffu

Posted 2015-07-14T02:40:34.627

Reputation: 1 361

0

JavaScript, 46/47 bytes

f=x=>[...x].map(c=>n+=c!=x[L++],n=L=-1)|L>0&&n/L

f=x=>[...x].map(c=>n+=c==x[++L],n=L=0)|L<2||n/--L

l4m2

Posted 2015-07-14T02:40:34.627

Reputation: 5 985

0

F# (.NET Core), 100 bytes

Whew, exactly 100 bytes. Too bad it's a bit verbose, I want to get it below 100. Determines chunkiness.

fun s->Seq.pairwise s|>fun s->Seq.sumBy(fun(x,y)->if x=y then 0. else 1.)s/float(max(Seq.length s)1)

Try it online!

snail_

Posted 2015-07-14T02:40:34.627

Reputation: 1 982

0

Kotlin, 52 bytes

Chunkiness:

{it.zipWithNext().count{(f,n)->f!=n}/(it.length-1f)}

Try it online!

snail_

Posted 2015-07-14T02:40:34.627

Reputation: 1 982

0

PowerShell, 55 bytes

Smoothness

%{$s=$_;@([char[]]$s|?{$_-eq$a;$a=$_;$i++}).count/--$i}

Seems a little bit silly to get a variable in stdin and then give it an identifier, but its quicker than having a function.

Nacht - Reinstate Monica

Posted 2015-07-14T02:40:34.627

Reputation: 481

0

Python 3, 61 Bytes

calculate chunkiness:

f=lambda s: sum(a!=b for a,b in zip(s,s[1:]))/max(len(s)-1,1)

TheCrypt

Posted 2015-07-14T02:40:34.627

Reputation: 141

0

K (22)

tweaked WooiKent's Q solution:

{1^(+/x)%#x:1_=':(),x}

scottstein37

Posted 2015-07-14T02:40:34.627

Reputation: 181

0

Ruby, 63 Bytes

Outputs chunkiness.

f=->s{s.chars.each_cons(2).count{|x,y|x!=y}/[s.size-1.0,1].max}

Similar to @daniero's solution, but slightly shortened by directly dividing by the string length - 1 and then relying on .count to be zero with length 0 & 1 strings (the .max ensures I won't divide by 0 or -1).

dgollahon

Posted 2015-07-14T02:40:34.627

Reputation: 1

0

Mathematica, 107 bytes

Calculates chunkiness by taking half of the Levenshtein distance between each digraph and its reverse.

f[s_]:=.5EditDistance@@{#,StringReverse@#}&/@StringCases[s,_~Repeated~{2},Overlaps->All]//Total@#/Length[#]&

If you'd prefer an exact rational answer, delete .5 and place a /2 before the last & for no penalty. The program itself has chunkiness 103/106, or about .972.

hYPotenuser

Posted 2015-07-14T02:40:34.627

Reputation: 707

0

K5, 24 bytes

{(r;1)@^r:(#&=':x)%#1_x}

Calculates smoothness. Seems to use a very different algorithm from K/Q/J/APL answers.

kirbyfan64sos

Posted 2015-07-14T02:40:34.627

Reputation: 8 730