「配列のすべての要素が条件を満たすならtrueを返す」関数に空配列を渡したらtrueかfalseか? 280
ストーリー by nagazou
関数 部門より
関数 部門より
あるAnonymous Coward 曰く、
ここ数日、Twitterのプログラマー界隈で「「配列のすべての要素が条件を満たすならtrueを返す」関数を定義するとき、空の配列を渡したらfalseを返すかtrueを返すかが、良いプログラマかどうかの一つの境目だ」というツイートを発端として、様々な意見が交わされているので、スラドにも共有したい。
発端となったのは上記のツイートだが、そのリプライや引用では「仕様によるのでは」「メソッド名次第」「コメントに書けばどちらでも良い」「使い方を間違えている可能性があるから例外を投げるべきだ」といったfalse肯定派もいれば、一方で「世の中の標準ライブラリはみんなtrue」「"配列のすべての要素が条件を満たすなら"なのだから論理的に考えてtrueに決まっている」という当然trueであるべきという主張も飛び交っている。
まさかこんなネタがこんなに盛り上がるとはという声もあるが、スラド諸氏はどうお考えだろうか?
「例外を投げる」はfalse肯定派じゃないだろ (スコア:5, 興味深い)
例外を投げる派はtrue派でもfalae派ででもないだろ
Re:「例外を投げる」はfalse肯定派じゃないだろ (スコア:1)
(現にある)実装での話ではなくて関数の定義の話なら例外しかないよね
プログラマーの優劣の話なら仕様不備でエスカレーションして決めてもらう
仕様の不備を勝手に埋めて自分勝手な論理で有効値を返すコーディングをするようなプログラマーは最低最悪。空の配列
プログラミングは数学や哲学ではない (スコア:4, すばらしい洞察)
「配列のすべての要素が条件を満たすなら真」という定義で「入力が空集合なら、返り値は真か偽か」ってのは
数学・論理学やそこら辺の話で、
現実のプログラミングでは「関数を書く者がその想定する用途にあわせて定義し、その定義を関数の説明に明示すること」、
「関数を使う人はそういう極端なケースが起きた場合の振る舞いに気を付けること」と言うので済む話。
Re:プログラミングは数学や哲学ではない (スコア:1)
同意します。
この件は定期的に湧く「数学も出来ないプログラマなんてマウント」の亜種ですね。
Re:プログラミングは数学や哲学ではない (スコア:2, すばらしい洞察)
でもこの程度のブール代数の素養すらなければ、アプリケーションの中で条件式を正しく書くのは困難だよね。
少なくとも職業プログラマとしては失格だ。
Re:プログラミングは数学や哲学ではない (スコア:1)
いや、挙動を明示すべきじゃなかろうか。
その関数の目的は数学的に正しい事を目指すものではないし、
「配列のすべての要素が条件を満たすならtrueを返す」という動作だけを指定しているのがそもそもの過ちで、
空の配列を渡した場合の動作も定義すべきだった。
そういう中途半端な事をしておいて「空の配列を渡したらfalseを返すかtrueを返すかが、良いプログラマかどうかの一つの境目だ」と」などと言い出すのが根本的に間違っていると思う。
さらに、「「メールのすべての添付ファイルが安全であれば受信箱に入れる」という処理において、添付ファイルのないメールはどうすべきかを考えれば、自然と答えがイメージしやすい」
とか言ってるけど、添付ファイルが無いものに対して添付ファイルが安全であるかどうか調べる、という動作を想定するのがおかしい
添付ファイルが存在する場合、添付ファイルが存在しない場合、それぞれに対する挙動を指定すべきなのに、「どうすべきかを考えれば」
じゃないだろう。
現実的には (スコア:3, 参考になる)
こういうのはエラーチェックのために使うことが多いので
条件を満さない要素が1つでもあればfalseで空ならtrueが普通と思う。
空かどうかはまた別のチェックということで。
Re:現実的には (スコア:1)
私はこれに同意。
ほかには、絞り込み検索の実装にも使いますね。
ある要素が全ての絞り込み条件に適合していれば抽出する、って処理を書くときに、「絞り込み条件が空の場合は適合」となっているとシンプル。
Re: (スコア:0)
こういうのはエラーチェックのために使うことが多いので
条件を満さない要素が1つでもあればfalseで空ならtrueが普通と思う。
空かどうかはまた別のチェックということで。
その用途だと「(別に行われてるべき)空チェックを正しくされてない」ことを検出できる、例外を投げる動作が一番理にかなってない?
Re: (スコア:0)
現実的にはって言うなら、自分の場合は、StreamAPI的に、配列にfilter()とかmatch()とかfind()とかで訊ねる、そういう感じで書く
だからまず「配列を渡してtrueかfalseを返させる」って状況設定が変だし、trueが返ってくるのも気持ち悪い
「エラーチェックのため」ならそう仕様に書けばいいっていうかそう書くべきで、一律にtrueを返すべきとかの暗黙の了解に委ねるのはちょっと怖いね
良いプログラマなら、そこで仕様を確認するか、他の原則を適用して判断して欲しいと思う
Re:現実的には (スコア:2)
∀(all_of)と、∃(exist, any_of)を混同したらダメだよ。
メソッド名から察するに、isVisibleItemExists は、「Visibleなアイテムが一つでも存在する場合、true」で、
その場合は空ならfalseが普通。
今回の仕様問題に合わせて「全ての要素が」という仕様の書き方をするなら、
「全ての要素が非visibleの場合は、falseを返す」
という仕様記述になり、
(返すtrue/falseが逆なので「元の仕様問題では空の場合はtrueを返すのが普通」と同じ話として)、
空の場合はfalseを返すの普通、となる。
言葉尻? (スコア:2)
空の配列には、条件を満たす要素は一つも無い。
つまり、falseだと思う。
Re:言葉尻? (スコア:4, すばらしい洞察)
「すべての要素が条件を満たすか?」というだけ話に、「かつ最低でも一つは条件を満たすこと」という別の条件を勝手に加えて判断してるね
論理的にも等価に言い換えるなら、「いずれかの要素が条件を満たさないことはないか?」だよ
A and B and ... = not(notA or notB or ...)
空配列は空であるが故に、いずれかの要素が条件を満たさないことはない、のでtrue
Re:言葉尻? (スコア:2, 参考になる)
知識がないので分かったと勘違いしてるな
n=0 の場合は未定義、なんてことはない
要素をゼロの空集合は、ある条件に合致する集合に必ず含まれる、というのは論理的に定義されてるルールだ
https://wiis.info/math/set/set/empty-set/ [wiis.info]
空集合は任意の集合の部分集合です。
君がその基礎的なルールを知らんから間違ってるように見えるだけ
n=0の場合、空集合となるので、右辺の集合の一部
当然、左辺の集合の一部も式通りに成り立つので、論理的にも矛盾しない
そして、逆にfalseとする場合は式が成り立たずに矛盾するので間違い
なのでtrueしかありえない
Re:言葉尻? (スコア:1)
数学およびその一分野であるコンピュータサイエンスでは、true になるで合ってるよ。
「∀A∈S に対して C(S)=真」が条件式なんだから、Sが空集合なら式は真になる。
論理積計算ではないの? (スコア:2)
「配列のすべての要素が条件を満たすならtrueを返す」関数というのは、配列の要素毎の条件判定の論理積を返す、と解するのが自然な気がする。Excel の AND 関数みたいな。
論理積を計算するのにパラメータが 0個だったら、やっぱり例外を投げるべきではないかな。
とは言え、そもそも人によって正解とするプログラムが違うのだったら仕様の定義が問題だと思うけど。
Re:論理積計算ではないの? (スコア:2)
その理屈だとパラメータが1個の場合も論理積を計算できないのでは?
イメージとしては excel の and 関数で、パラメータは 1個以上かな、と。
もしくはベン図でいうと配列要素数分の真の重なり部分かどうかを返す関数と考えれば、1つの真偽の集合しか与えられなくても答えは出る、と。
i=1 から n までの総和Σにおいても、n=1 のときは要素単体ですが、n=0 のときに単位元 0 を返すのは約束事もしくは定義であって自明のことではないのでは、という認識でいます。今回の関数は総和ならぬ総論理積だと思うので、問いは空論理積はどうあるべきか、という話ではないでしょうか。
# 自信なし
Wikipedia の空和や空積の説明には「定義することの妥当性」という項があり、これに従えば総論理積でも同様に単位元(=真)を返すと「定義するのが妥当」なのかもしれません。この妥当性を当然と感じるセンスが「良いプログラマかどうかの一つの境目」と言いたいのかな?
私の感覚としてはきちんとドキュメント化する(またはドキュメント化を要求する)方が良いプログラマではないか、というのは変わりませんが。
% irb
irb(main):001:0> [1,2,3].all?{ |x| x > 0 }
=> true
irb(main):002:0> [1].all?{ |x| x > 0 }
=> true
irb(main):003:0> [].all?{ |x| x > 0 }
=> true
Ruby 3.2 リファレンスマニュアル Array#all? [ruby-lang.org] 空配列については書かれていないけど、自明というスタンスなのかな…
Re:言葉尻? (スコア:1)
けど、私が普通にプログラムを書くと
①返り値の初期値としてTRUEをセット
②要素を一つづつチェックして、条件を満たさなければ返り値にFALSEをセット
(FALSEになったらその先の要素のチェックはスキップ)
という感じになるから、要素が0だとTRUEを返してしまいそうだ。
やっぱり要件に「要素数が0の時の返り値」を指定してくれないと、最初に要素数のチェックまで思い至らないかも。
Re: (スコア:0)
同意。
条件がキモで、
大抵は配列の中にある値を使用して判定するよね
まずは条件を定義してからの話ですね
Re: (スコア:0)
ところが、「店内で飲酒している人が全員20歳以上なら適法」という判定に「空ならfalae」を使うと、店内に客がいなかったり全員がノンアルを飲んでいたりするとアウトになってしまう。
で、なぜかロジックは修正されず「誰か常に酒を飲む奴を配置する」なんてパッチが当てられたりするわけですな(笑)
Re: (スコア:0)
そらそうよ
知りたいのは、店内に20歳未満なのに飲酒してるやつがいたら違法
であって適法かどうかはどうでもいいもの
要は仕様バグってこと
Re: (スコア:0)
「店内で飲酒している人が一人でも20歳未満なら違法」という判定に「空ならtrue」を使うと?
Re:言葉尻? (スコア:1)
「一人でも」はallじゃなくてanyでしょ。
anyは配列が空ならfalseを返す。
Re:言葉尻? (スコア:1)
老眼が始まったかもしれない
Re: (スコア:0)
Segmentation falutだったりして
Re: (スコア:0)
言葉尻ではなく本質だろう。
そういう所を定義するのが良いプログラマ。
これについては、問題の性質によるので、
プログラムとしては「どれもありえる」。
曖昧な処理は、仕様書に明記しろってことだな。
Re:言葉尻? (スコア:1)
配列の「すべての要素」は「全N個のうちN個」だし、
配列は要素数に0を許すのだから正だと思いますが。
trueが正解 (スコア:2, 参考になる)
falseが正解と書いてる人が居るので念のために言っておくが"true"が正解。
これは論理学的には「Vacuous truth」で「全ての集合は空集合を部分集合として含む」「前提が偽なら命題は真(爆発律)」のように正当化される。
空の場合は「全てが条件を満たす」で日本語的にもあってる。
要素数が1兆・1億・1まで真な関数が0になると急に偽を返すのも直感に反する。
プログラマーとしても最初はtrueで宣言したboolに&=したり、while(){}内でreturn false、外で`return true`したり、どう考えてもtrue。
論理学なんかクソくらえと思うかもしれないが、論理学的にそうなら実務でも一貫してる。具体的な状況は、
逆に空でfalseを返すべき状況は個数判定をすれば十分で、また0個が特別な意味を持つと考えた方が自然なケース。
(なお単に「trueを返す」という条件だと空でもtrueが一貫してると言おうと思ったが、「falseを返す」だと空でfalseを返しそう。)
個人的にはどうしても0個のケースを意識させたいならfalseや例外じゃなくてコールバック関数版を追加でもして欲しいところ。
例外はJavaのように検査例外を採用してないと見逃す。こんな挙動は予想できん。
falseはキレられ損害賠償でも当然。
Re:trueが正解 (スコア:1)
> 1個も満たしてない
「1個は満たすこと」という条件はどっから出てきたんだ?
条件は明示されてるのになんで存在しない条件を勝手に加えるのか
1個あるかどうかの話するなら当然条件式全体も等価に変換しろ
つまり「すべて」ではなく「いずれか」の条件式に変換
すべての配列(内の要素)が3桁の数字であること=いずれかの要素が3桁の数字ではないことがないこと
はい、空集合ならtrueなのが明白だな
ベン図でも書いてみろ
真を返す方が簡潔に書ける (スコア:2)
and (x:xs) = x && and xs
ただし思わぬバグになる可能性があるので,不親切な気もする.
仕様を決めたか、決めなかったか、それが問題なだけだ (スコア:1)
純粋に処理の面だけで言えば変数(この場合は関数の返り値)の操作なんてInitとSetとGetの3つしかないんだから、
これは良いプログラマかどうかなんて話じゃなくて
(1)返り値のInitで何をセットするか
(2)条件チェック処理で、条件を満たさないelseのケースでも返り値に何かをSetするか
という仕様を決めて実装するかどうかだけのことじゃないの?
もちろん仕様はありません動いているように動きます、ってのは論外だが、それが現場のプログラマの良し悪しだけで決まるかと言われると、、
個人的には(1)でfalseをセットして、(2)ではelseでは何もセットしない(Setするのはifのケースのみ)だったことが多いかな。
ツィートに似たケースとしては、ある{ステータス, イベント}のセットを受けて処理をする関数配列が思い浮かんだので、
ここで空の配列が来た場合はどの関数も走らせちゃいけないからfalseを返させると思う。
例外をthrowするかどうかはそのfalseを受けた後処理で決める。
でもこうやって具体的に考えてみると(1)についてはtrueで返り値をInitするケースがないとは言い切れないな、
ただ(2)で条件を満たさなくても返り値に何かをSetするケースは思い当たらないかも(条件合致以外で返り値の操作が必要なのはそもそもスジが悪い、ハズ)
いずれにせよ仕様の思考実験としては面白いけど、これでプログラマーの良し悪しが分けられるとは思わないな。
//知ってるか? 人間は大きく2つに分けると死んじゃう [twitter.com]んだぜ?
というか (スコア:1)
なぜこれが良いプログラマかどうかの判定にできるのかの根拠を知りたい。
自分の狭い経験だけで、単純に判定しようとする人とは仕事したくないなあ
Re:というか (スコア:1)
自分はこれは悪くないひとつの判定基準だと思う
入力された配列のすべての要素が条件を満たす場合に~ってときに空配列が入ってきた場合を聞くのはその人が問題をどう扱うかを見れる
回答は「このライブラリではtrueになります」とか「前職のプロジェクトではfalseになってました」でもいいんですよ
一番ききたいのはそのtrue/falseにした理由
そこでもし筋の通った理屈で問題を解決していればOK、もしも「このライブラリではそうなっています」とか
「過去のプロジェクトでそうなっていたからです」という理由しか出てこなかったらNGね
自分は良いプログラマというのは良い問題解決者でもあると考えているので、そういう意味でこれは良い質問かな、と
何をしたいかが (スコア:1)
何をしたいかが重要で、
それを明示するor明示されていなければ指摘して明示させるのがよいプログラマだと思う。
配列に格納するのがなんかの調査データだったとして、空に対する戻り値は、何をしたいかによって次のとおり
全ての条件を満たす優良事例を調べたい→良い条件が検出できないので、false
条件に適合しない悪い事例を抽出したい→悪い条件が検出されないので、true
入力されたデータを洗いたい→再入力等をさせるため、例外
アルバイトの面接での出来事 (スコア:1)
30年前、学生だった時にプログラマのアルバイトに応募し、
一対一の面接のなかで、「このプログラムコードを書け」という紙が渡された。
確か、九九の表を作るような問題だったのだが、
「出力例」の表は、一行ほど計算間違いが含まれていた。
自分は、「ああ、誰かが打ち間違えたんだな」と思い、そのまま九九のコードを作って提出した。
結果、面接に落ちた。
結果に納得できずしばらく憮然としたが、
今となっては、あれは「出力例について質問して聞く」が正解だったのではないかと思っている。
つまり、コード作成能力ではなく「わからないことを聞く」というビジネスの基本を問うていたのだ。
このトピックの問題も、もしあなたが何かのプロジェクトの一員としてこの問題に直面したのなら、
正解はtrueでもfalseでもerrorでもなく、「質問して聞く」が正解なのではないだろうか。
0は自然数か? (スコア:1)
// うっかり「0は整数じゃねー」みたいな返答をしている人もいてカオス
これでわかるのはプログラムの経験値だけでは (スコア:0)
良い悪いはない
falseじゃないんですか?ちょっと誰か説明して・・・ (スコア:0)
> 「配列のすべての要素が条件を満たすならtrueを返す」関数を定義するとき、
> 空の配列を渡したらfalseを返すかtrueを返すか
https://www.perplexity.ai/ [perplexity.ai] :
"「配列のすべての要素が条件を満たすならtrueを返す」関数を定義するとき、空の配列を渡した場合、trueを返すべきです1
2
3
。空の配列は、すべての要素が条件を満たすという要件に反するものではなく、真偽値を返す関数においては、空の配列を渡した場合にtrueを返すことが多いです。また、空集合はあらゆる集合の部分集合であるため、空の配列を渡した場合にfalseを返すと、ある種の矛盾が生じることになります1
。ただし、空の配列を渡した場合にfalseを返すという設計もあるため、プログラマーによって異なる場合があります。"
> 空の配列は何も入っておらず、条件を満たすかどうかを比較する「要素」を含んでいない。だからfalseを返すべきではないのか
"空の配列を渡した場合、すべての要素が条件を満たすという要件に反するものではなく、真偽値を返す関数においては、空の配列を渡した場合にtrueを返すことが多いです1
2
3
。空の配列を渡した場合にfalseを返すという設計もあるため、プログラマーによって異なる場合があります2
。空の配列は何も入っておらず、条件を満たすかどうかを比較する「要素」を含んでいないため、空の配列を渡した場合にfalseを返すべきだと考える人もいます4
5
。ただし、空集合はあらゆる集合の部分集合であるため、空の配列を渡した場合にfalseを返すと、ある種の矛盾が生じることになります1
。したがって、空の配列を渡した場合にtrueを返すことが一般的です。"
Re:falseじゃないんですか?ちょっと誰か説明して・・・ (スコア:1)
とりあえず、書き込みする前に表示をチェックしないやつは良いプラグラマじゃない
ついでに言うならせっかくコピーボタンが用意されてるのに、範囲指定で手作業コピペとかやるやつも向いてない
で、説明しても何も『空集合はあらゆる集合の部分集合』って2度も書いてあるだろ
『その配列は条件を満たす集合の部分集合か』ってのと同じなんだから空配列はtrueを返しとくのが無難とAI君はいってる
falseと回答した人は首な (スコア:0)
来週の会議で聞いてみよっと
=18){$count_pass++;}}
return ($count_all == $count_pass)?true:false;
}
var_dump( returnTrueIfAllOver18([20,30,40,50,60]) );// true
var_dump( returnTrueIfAllOver18([1,3,5,10,90]) );// false
var_dump( returnTrueIfAllOver18([]) );// true
Re: (スコア:0)
コードが崩れた
Re:falseと回答した人は首な (スコア:1)
18未満があったらそこで処理を打ち切る方が早いと思われる。
function returnTrueIfAllOver18($array){
foreach($array as $a){if ($a<18){ return false; }}
return true;
}
# SlashDot Light [takeash.net] やってます。
Re:falseと回答した人は首な (スコア:1)
Re: (スコア:0)
理解できないからってひがむなよ
Re: (スコア:0)
君みたいな人が覗きに来ている方が謎なんだが
Re:迷う余地などなく「false」を返すのが正しい。 (スコア:1)
何度か考えたのですが、0個の要素全てについて条件判定した結果、OKなのでtrueになる。
全くピーマンが入っていない料理を平らげた子供が「出されたピーマンを全て食べました。」と言ったとき、それは嘘ではないからtrueです。
Re:迷う余地などなく「false」を返すのが正しい。 (スコア:1)
// 数学からすると 1+1 = 0か1か2か
Re:実際にやってみた (スコア:2, 参考になる)
仕様くらい調べてから書け
https://docs.python.org/3/library/stdtypes.html [python.org]
str.isalpha()
Return True if all characters in the string are alphabetic and there is at least one character
str.isascii()
Return True if the string is empty or all characters in the string are ASCII
明言されてる仕様通りだ
isalphaは『最低1文字以上のすべての文字が』が条件なんだからそのやりかたならFalseが帰るのが当然であり、
isasciiは『すべての文字が』が条件でしかないのでタレコミに対する解と同じくTrueになる。(親切にわざわざEmptyでもと書いてある)
Re:qsort関数の場合は? (スコア:1)
ワイルドポインタでもないのにqsortがコアを吐くっておおごと。Javaで言えば特定のコードでvmが落ちちゃうのに等しいよね。Javaの例外と同一視するって、問題ありすぎだろう。
富士通japan の人なのかなw
Re:LISPは (スコア:1)
// map関数に空配列与えたら nil が帰ってくるのはある意味当たり前で話題の問題とはまた別