Predicate testing for equality that returns the common element
$begingroup$
I'm going to try brute-forcing the solving of a Magic Square. To simplify the code later on, I wanted a function similar to =, but one that returns the common element if all the elements are equal and nil otherwise. This is unlike = which always returns either true or false. I'm calling it =? for lack of a better name.
Example:
(=? 1 2 1)
nil ; nil because they're not all the same
(=? 1 1 1)
1 ; Returns the common element of 1
Obviously, this function won't work well when nil may be the sole element in a collection, since it will return falsey even if all the elements are the same, but nil.
I thought that there must be some kind of core operation I could use here, but after a few minutes of thinking, I couldn't think of any. I ended up rolling my own function using loop. I'd like general advice on the function that I wrote, or potentially a more idiomatic way to write it that I'm missing. It looks exceedingly clunky to me; especially after I realized the need for the last-arg accumulator. A recursive solution would be nice, as I fear I'm missing something obvious here:
(defn =?
"Checks if every supplied argument =s every other.
Returns the common element if they're all the same, nil otherwise."
[& args]
(loop [[f-arg & r-args] (rest args)
last-arg (first args)]
(cond
(nil? f-arg) last-arg
(= f-arg last-arg) (recur r-args f-arg)
:else nil)))
clojure
$endgroup$
add a comment |
$begingroup$
I'm going to try brute-forcing the solving of a Magic Square. To simplify the code later on, I wanted a function similar to =, but one that returns the common element if all the elements are equal and nil otherwise. This is unlike = which always returns either true or false. I'm calling it =? for lack of a better name.
Example:
(=? 1 2 1)
nil ; nil because they're not all the same
(=? 1 1 1)
1 ; Returns the common element of 1
Obviously, this function won't work well when nil may be the sole element in a collection, since it will return falsey even if all the elements are the same, but nil.
I thought that there must be some kind of core operation I could use here, but after a few minutes of thinking, I couldn't think of any. I ended up rolling my own function using loop. I'd like general advice on the function that I wrote, or potentially a more idiomatic way to write it that I'm missing. It looks exceedingly clunky to me; especially after I realized the need for the last-arg accumulator. A recursive solution would be nice, as I fear I'm missing something obvious here:
(defn =?
"Checks if every supplied argument =s every other.
Returns the common element if they're all the same, nil otherwise."
[& args]
(loop [[f-arg & r-args] (rest args)
last-arg (first args)]
(cond
(nil? f-arg) last-arg
(= f-arg last-arg) (recur r-args f-arg)
:else nil)))
clojure
$endgroup$
add a comment |
$begingroup$
I'm going to try brute-forcing the solving of a Magic Square. To simplify the code later on, I wanted a function similar to =, but one that returns the common element if all the elements are equal and nil otherwise. This is unlike = which always returns either true or false. I'm calling it =? for lack of a better name.
Example:
(=? 1 2 1)
nil ; nil because they're not all the same
(=? 1 1 1)
1 ; Returns the common element of 1
Obviously, this function won't work well when nil may be the sole element in a collection, since it will return falsey even if all the elements are the same, but nil.
I thought that there must be some kind of core operation I could use here, but after a few minutes of thinking, I couldn't think of any. I ended up rolling my own function using loop. I'd like general advice on the function that I wrote, or potentially a more idiomatic way to write it that I'm missing. It looks exceedingly clunky to me; especially after I realized the need for the last-arg accumulator. A recursive solution would be nice, as I fear I'm missing something obvious here:
(defn =?
"Checks if every supplied argument =s every other.
Returns the common element if they're all the same, nil otherwise."
[& args]
(loop [[f-arg & r-args] (rest args)
last-arg (first args)]
(cond
(nil? f-arg) last-arg
(= f-arg last-arg) (recur r-args f-arg)
:else nil)))
clojure
$endgroup$
I'm going to try brute-forcing the solving of a Magic Square. To simplify the code later on, I wanted a function similar to =, but one that returns the common element if all the elements are equal and nil otherwise. This is unlike = which always returns either true or false. I'm calling it =? for lack of a better name.
Example:
(=? 1 2 1)
nil ; nil because they're not all the same
(=? 1 1 1)
1 ; Returns the common element of 1
Obviously, this function won't work well when nil may be the sole element in a collection, since it will return falsey even if all the elements are the same, but nil.
I thought that there must be some kind of core operation I could use here, but after a few minutes of thinking, I couldn't think of any. I ended up rolling my own function using loop. I'd like general advice on the function that I wrote, or potentially a more idiomatic way to write it that I'm missing. It looks exceedingly clunky to me; especially after I realized the need for the last-arg accumulator. A recursive solution would be nice, as I fear I'm missing something obvious here:
(defn =?
"Checks if every supplied argument =s every other.
Returns the common element if they're all the same, nil otherwise."
[& args]
(loop [[f-arg & r-args] (rest args)
last-arg (first args)]
(cond
(nil? f-arg) last-arg
(= f-arg last-arg) (recur r-args f-arg)
:else nil)))
clojure
clojure
edited Feb 9 '18 at 22:46
Carcigenicate
asked Feb 9 '18 at 21:49
CarcigenicateCarcigenicate
3,29211431
3,29211431
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
$begingroup$
Soon after I posted this, I went for a walk and realized that this is the perfect opportunity to use reduce. I'm kind of embarrassed that I didn't see it originally, but this was my train of thought that lead me to what I'm much happier with.
First, I tried a simple reduction. This was pretty simple, although still a little verbose:
(defn =?2 [& args]
(reduce (fn [acc n]
(if (= n acc)
n
(reduced nil)))
(first args)
(rest args)))
I decided that this was probably simple enough to use a function macro for. Normally I don't like using them for reductions, but there's not much going on here:
(defn =?3 [& args]
(reduce #(if (= % %2) % (reduced nil))
(first args)
(rest args)))
I don't like using explicit calls to first and rest, as I find they're usually neater when they're implicit in a deconstruction. I decided to deconstruct the arguments instead:
(defn =?4 [& [arg & rest-args]]
(reduce #(if (= % %2) % (reduced nil))
arg
rest-args))
Then I checked what = uses, and found that it just uses multiple argument lists, so I tried that. This strikes me as the more idiomatic solution:
(defn =?5
( nil)
([arg] arg)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
I'm torn between 4 and 5, but I think that both are a significant improvement.
$endgroup$
add a comment |
$begingroup$
You don't need the single argument case. You can abbreviate to
(defn =?5
( nil)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
However, the following is simpler still:
(defn =?
( nil)
([x & xs]
(when (every? #(= x %) xs) x)))
We can even fold in the zero-argument case in by destructuring, as you do in =?4:
(defn =? [& [x & xs]]
(when (every? #(= x %) xs) x))
But this is too obscure for me.
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f187221%2fpredicate-testing-for-equality-that-returns-the-common-element%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Soon after I posted this, I went for a walk and realized that this is the perfect opportunity to use reduce. I'm kind of embarrassed that I didn't see it originally, but this was my train of thought that lead me to what I'm much happier with.
First, I tried a simple reduction. This was pretty simple, although still a little verbose:
(defn =?2 [& args]
(reduce (fn [acc n]
(if (= n acc)
n
(reduced nil)))
(first args)
(rest args)))
I decided that this was probably simple enough to use a function macro for. Normally I don't like using them for reductions, but there's not much going on here:
(defn =?3 [& args]
(reduce #(if (= % %2) % (reduced nil))
(first args)
(rest args)))
I don't like using explicit calls to first and rest, as I find they're usually neater when they're implicit in a deconstruction. I decided to deconstruct the arguments instead:
(defn =?4 [& [arg & rest-args]]
(reduce #(if (= % %2) % (reduced nil))
arg
rest-args))
Then I checked what = uses, and found that it just uses multiple argument lists, so I tried that. This strikes me as the more idiomatic solution:
(defn =?5
( nil)
([arg] arg)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
I'm torn between 4 and 5, but I think that both are a significant improvement.
$endgroup$
add a comment |
$begingroup$
Soon after I posted this, I went for a walk and realized that this is the perfect opportunity to use reduce. I'm kind of embarrassed that I didn't see it originally, but this was my train of thought that lead me to what I'm much happier with.
First, I tried a simple reduction. This was pretty simple, although still a little verbose:
(defn =?2 [& args]
(reduce (fn [acc n]
(if (= n acc)
n
(reduced nil)))
(first args)
(rest args)))
I decided that this was probably simple enough to use a function macro for. Normally I don't like using them for reductions, but there's not much going on here:
(defn =?3 [& args]
(reduce #(if (= % %2) % (reduced nil))
(first args)
(rest args)))
I don't like using explicit calls to first and rest, as I find they're usually neater when they're implicit in a deconstruction. I decided to deconstruct the arguments instead:
(defn =?4 [& [arg & rest-args]]
(reduce #(if (= % %2) % (reduced nil))
arg
rest-args))
Then I checked what = uses, and found that it just uses multiple argument lists, so I tried that. This strikes me as the more idiomatic solution:
(defn =?5
( nil)
([arg] arg)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
I'm torn between 4 and 5, but I think that both are a significant improvement.
$endgroup$
add a comment |
$begingroup$
Soon after I posted this, I went for a walk and realized that this is the perfect opportunity to use reduce. I'm kind of embarrassed that I didn't see it originally, but this was my train of thought that lead me to what I'm much happier with.
First, I tried a simple reduction. This was pretty simple, although still a little verbose:
(defn =?2 [& args]
(reduce (fn [acc n]
(if (= n acc)
n
(reduced nil)))
(first args)
(rest args)))
I decided that this was probably simple enough to use a function macro for. Normally I don't like using them for reductions, but there's not much going on here:
(defn =?3 [& args]
(reduce #(if (= % %2) % (reduced nil))
(first args)
(rest args)))
I don't like using explicit calls to first and rest, as I find they're usually neater when they're implicit in a deconstruction. I decided to deconstruct the arguments instead:
(defn =?4 [& [arg & rest-args]]
(reduce #(if (= % %2) % (reduced nil))
arg
rest-args))
Then I checked what = uses, and found that it just uses multiple argument lists, so I tried that. This strikes me as the more idiomatic solution:
(defn =?5
( nil)
([arg] arg)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
I'm torn between 4 and 5, but I think that both are a significant improvement.
$endgroup$
Soon after I posted this, I went for a walk and realized that this is the perfect opportunity to use reduce. I'm kind of embarrassed that I didn't see it originally, but this was my train of thought that lead me to what I'm much happier with.
First, I tried a simple reduction. This was pretty simple, although still a little verbose:
(defn =?2 [& args]
(reduce (fn [acc n]
(if (= n acc)
n
(reduced nil)))
(first args)
(rest args)))
I decided that this was probably simple enough to use a function macro for. Normally I don't like using them for reductions, but there's not much going on here:
(defn =?3 [& args]
(reduce #(if (= % %2) % (reduced nil))
(first args)
(rest args)))
I don't like using explicit calls to first and rest, as I find they're usually neater when they're implicit in a deconstruction. I decided to deconstruct the arguments instead:
(defn =?4 [& [arg & rest-args]]
(reduce #(if (= % %2) % (reduced nil))
arg
rest-args))
Then I checked what = uses, and found that it just uses multiple argument lists, so I tried that. This strikes me as the more idiomatic solution:
(defn =?5
( nil)
([arg] arg)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
I'm torn between 4 and 5, but I think that both are a significant improvement.
edited Feb 9 '18 at 23:18
answered Feb 9 '18 at 23:12
CarcigenicateCarcigenicate
3,29211431
3,29211431
add a comment |
add a comment |
$begingroup$
You don't need the single argument case. You can abbreviate to
(defn =?5
( nil)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
However, the following is simpler still:
(defn =?
( nil)
([x & xs]
(when (every? #(= x %) xs) x)))
We can even fold in the zero-argument case in by destructuring, as you do in =?4:
(defn =? [& [x & xs]]
(when (every? #(= x %) xs) x))
But this is too obscure for me.
$endgroup$
add a comment |
$begingroup$
You don't need the single argument case. You can abbreviate to
(defn =?5
( nil)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
However, the following is simpler still:
(defn =?
( nil)
([x & xs]
(when (every? #(= x %) xs) x)))
We can even fold in the zero-argument case in by destructuring, as you do in =?4:
(defn =? [& [x & xs]]
(when (every? #(= x %) xs) x))
But this is too obscure for me.
$endgroup$
add a comment |
$begingroup$
You don't need the single argument case. You can abbreviate to
(defn =?5
( nil)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
However, the following is simpler still:
(defn =?
( nil)
([x & xs]
(when (every? #(= x %) xs) x)))
We can even fold in the zero-argument case in by destructuring, as you do in =?4:
(defn =? [& [x & xs]]
(when (every? #(= x %) xs) x))
But this is too obscure for me.
$endgroup$
You don't need the single argument case. You can abbreviate to
(defn =?5
( nil)
([arg & args]
(reduce #(if (= % %2) % (reduced nil))
arg
args)))
However, the following is simpler still:
(defn =?
( nil)
([x & xs]
(when (every? #(= x %) xs) x)))
We can even fold in the zero-argument case in by destructuring, as you do in =?4:
(defn =? [& [x & xs]]
(when (every? #(= x %) xs) x))
But this is too obscure for me.
edited 53 mins ago
answered 1 hour ago
ThumbnailThumbnail
1,366510
1,366510
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f187221%2fpredicate-testing-for-equality-that-returns-the-common-element%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown