Skip to content

Instantly share code, notes, and snippets.

@gilesbowkett
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gilesbowkett/b18af441e81747f10143 to your computer and use it in GitHub Desktop.
Save gilesbowkett/b18af441e81747f10143 to your computer and use it in GitHub Desktop.
what's the best way to satisfy this Midje test?
(facts "about finding sub-words"
(fact "(sub-words) finds all possible sub-words"
(sub-words "monocarp") => ["mono",
"monoc",
"monoca",
"monocar",
"onoc",
"onoca",
"onocar",
"onocarp",
"noca",
"nocar",
"nocarp",
"ocar",
"ocarp",
"carp"]))
@gilesbowkett
Copy link
Author

the basic idea here is to get all substrings >= 4 characters and <= 8. (they don't actually have to be in any particular order, that's just how I wrote the test.)

@gilesbowkett
Copy link
Author

it kind of needs to do this, so I'm thinking it'll be a list comprehension:

welder.core=> (subs "monocarp" 0 4)
"mono"
welder.core=> (subs "monocarp" 0 5)
"monoc"
welder.core=> (subs "monocarp" 0 6)
"monoca"
welder.core=> (subs "monocarp" 0 7)
"monocar"
welder.core=> (subs "monocarp" 1 5)
"onoc"
welder.core=> (subs "monocarp" 1 6)
"onoca"
welder.core=> (subs "monocarp" 1 7)
"onocar"
welder.core=> (subs "monocarp" 1 8)
"onocarp"
welder.core=> (subs "monocarp" 2 6)
"noca"
welder.core=> (subs "monocarp" 2 7)
"nocar"
welder.core=> (subs "monocarp" 2 8)
"nocarp"
welder.core=> (subs "monocarp" 3 7)
"ocar"
welder.core=> (subs "monocarp" 3 8)
"ocarp"
welder.core=> (subs "monocarp" 4 8)
"carp"

@gilesbowkett
Copy link
Author

my solution

(defn sub-words [word]
  (vec (filter (fn [subword]
                   (and (< 3 (.length subword))
                        (not (= word subword))))
               (for [start (range 0 5), end (range 4 9)] (subs word start end)))))

advice still welcome, though, I wouldn't be shocked if there were a cleaner way to do it.

@hotwoofy
Copy link

There are more efficient ways to do it that just iterate over the correct bounds, but I quite like:

(defn sub-words
  ([^String s] (sub-words s 4))
  ([^String s ^Integer min-length]
   (vec (for [start (range 0 (.length s))
              length (range min-length (.length s))
              :let [end (+ start length)]
              :when (<= end (.length s))]
          (subs s start end)))))

@hotwoofy
Copy link

But even in your example, if you find yourself filtering the results of a for then you might sometimes look at using :let and :when.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment