152 views
Skip to first unread message

John Holland

unread,
Jul 29, 2012, 9:07:18 AM7/29/12
to clo...@googlegroups.com
I'm doing some exercises in coding that are meant for Java but I'm doing them in Clojure. I'm stuck on this one. The goal is
to return true if an array of ints contains two consecutive 2s. I figured I'd use Stuart Halloway's by-pairs function to turn the sequence
into pairs of numbers and check for a pair that is 2,2.  This code in has22 below works if pasted into the REPL and evaluated but as a
function it always returns false. If anyone can explain my error to me it'd be great.







(  defn by-pairs [coll] (let [take-pair (fn [c]
                                         (when (next c) (take 2 c)))] (when-let [pair (seq (take-pair coll))]
                                                                        (lazy-seq
                                                                         (cons pair (by-pairs (rest coll)))))))

(defn has22 [a]   (if (some true? (map  #(= 2 (first %) (nth % 1)) (by-pairs [a]))) true false))



user> (some true? (map  #(= 2 (first %) (nth % 1)) (by-pairs [1 2 2 2 ])))
true


user> (has22 [1 2 2 2])
false


John Holland

Mark Rathwell

unread,
Jul 29, 2012, 9:19:38 AM7/29/12
to clo...@googlegroups.com
In your has22 definition, (by-pairs [a]) should be (by-pairs a)
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

Moritz Ulrich

unread,
Jul 29, 2012, 9:22:01 AM7/29/12
to clo...@googlegroups.com
Also, take a look at `partition'.

John Holland

unread,
Jul 29, 2012, 9:25:14 AM7/29/12
to clo...@googlegroups.com
Thanks!
______________________________________

Note new email address jbho...@gmail.com

Ulises

unread,
Jul 29, 2012, 2:16:29 PM7/29/12
to clo...@googlegroups.com
Here's an edge case for you:

(has22 [1 2 2 1]) ; false

:)

U

Yoshinori Kohyama

unread,
Jul 29, 2012, 11:22:11 PM7/29/12
to clo...@googlegroups.com
Hi John,

'partition' will be useful for you, as Moritz pointed out.

(partition 2 1 [1 2 3 4]) -> ((1 2) (2 3) (3 4))
(partition 2 1 [1 2 2 4]) -> ((1 2) (2 2) (2 4))
(partition 2 1 [1 2 2 2]) -> ((1 2) (2 2) (2 2))

(some #(= % [2 2]) (partition 2 1 [1 2 3 4])) -> nil
(some #(= % [2 2]) (partition 2 1 [1 2 2 4])) -> true
(some #(= % [2 2]) (partition 2 1 [1 2 2 2])) -> true

(filter #(= % [2 2]) (partition 2 1 [1 2 3 4])) -> ()
(filter #(= % [2 2]) (partition 2 1 [1 2 2 4])) -> ((2 2))
(filter #(= % [2 2]) (partition 2 1 [1 2 2 2])) -> ((2 2) (2 2))

I'm sorry I can't recognize whether you need a pair of 2s or two pairs of 2s.

If you need one or more pairs of 2s, do
(defn has22 [coll] (boolean (some #(= % [2 2]) (partition 2 1 coll))))
(has22 [1 2 3 4]) -> false
(has22 [1 2 2 4]) -> true
(has22 [1 2 2 2]) -> true

If you need two or more pairs of 2s, do
(defn has222 [coll] (< 1 (count (filter #(= % [2 2]) (partition 2 1 coll)))))
(has222 [1 2 3 4]) -> false
(has222 [1 2 2 4]) -> false
(has222 [1 2 2 2]) -> true

Regards,
Yoshinori Kohyama

Ben Smith-Mannschott

unread,
Jul 30, 2012, 7:45:28 AM7/30/12
to clo...@googlegroups.com
In an effort to increase the net amount of perversity in the universe,
I offer the following alternate solution:

(defn has22 [a]
(->> (concat [""] (map str a) [""])
(interpose " ")
(apply str)
(re-find #" 2 2 ")
boolean))

;-)

// Ben

DeWitt Clinton

unread,
Jul 30, 2012, 12:53:42 AM7/30/12
to clo...@googlegroups.com
I really like the 'partition' technique. That said, as a non-expert, I find the recursive approach marginally easier to read:

(defn has22 [coll]
  (when-let [s (seq coll)]
    (or (= 2 (first s) (second s)) (recur (rest s)))))

In my microbenchmarks, the above technique runs about 5-10x faster for all sequences.  Close enough that I suspect it is largely a matter of personal preference, but still slightly faster on my machine.

As a footnote, using destructuring instead ran only about half as fast as the above code:

(defn has22-destructing [coll]
  (when-let [[x & xs] (seq coll)]
    (or (= 2 x (first xs)) (recur xs))))

Not entirely sure why that would be.

Best regards,

-DeWitt


--

nicola...@gmail.com

unread,
Jul 30, 2012, 12:08:41 PM7/30/12
to clo...@googlegroups.com
Another one. (The exception is for early termination)

(def found! (Exception.))

(defn has22 [l]
(try
(reduce #(and (= 2 %2) (or (not %1) (throw found!))) false l)
false
(catch Exception e true)))

Yoshinori Kohyama

unread,
Jul 30, 2012, 11:41:10 PM7/30/12
to clo...@googlegroups.com
Hi Nicolas,

The technique, using throw an Exception when succeeded in searching, strikes me!
Not idiomatic but very practical.
It's like a break in a loop of imperatives.
I may use it somewhere.
Thank you.

Regards,
Yoshinori Kohyama

nicola...@gmail.com

unread,
Jul 31, 2012, 5:37:47 AM7/31/12
to clo...@googlegroups.com
> The technique, using throw an Exception when succeeded in searching, strikes
> me!

You can make it less ugly with a bit of library:

user> (deftype EarlyExit [result])
user.EarlyExit
user> (defn early-exit [x] (EarlyExit. x))
user> (defn reduce-with-early-exit [f acc coll]
(if (instance? user.EarlyExit acc)
(. ^EarlyExit acc result)
(if-let [hd (first coll)]
(recur f (f acc hd) (rest coll))
acc)))

Then you can write:

(defn has22 [coll] (= (reduce-with-early-exit #(and (= %2 2) (or (not
%1) (early-exit :found!))) false coll) :found!))

You can write early-exit and reduce-with-early-exit by using a Throwable.
Whichever is best depends on how often you exit early and how long is
your sequence.

Yoshinori Kohyama

unread,
Aug 1, 2012, 1:42:49 AM8/1/12
to clo...@googlegroups.com
Hi Nicolas,

Thank you for teaching!
I often use very long sequences and often want to terminate in middle of folding operations of them.
With reduce, code come to be simple and abstract, but I couldn't terminate them.
So I used to use loops or wrapping functions using loop.

Throwing a throwable object is a good alternative for me.

Thank you again.

Regards,
Yoshinori Kohyama
Reply all
Reply to author
Forward
0 new messages