No.7ベストアンサー
- 回答日時:
私が#5で書いたものでは通じていないようなので、もう一度まとめさせていただきました。
この関数の原型は、LotusグループからIBMにノウハウが移動したものを、マイクロソフトの開発チームがあれこれと考えて、手を加えたものだとは思います。その仕組みを知りたいというなら、C言語や、せめてVBAで同じ表現ができるように作ってみて、ある程度の概要が分かるもので、それをワークシート上では、表面的なものでしか分からないと思います。
また、私は、その中身を、深く追求するような興味はありませんでしたが、少々、このままでは、治まらないので、VBAで作ってみました。文字比較とは言っても、文字コードではなく、バイナリ比較(binary compare[ワークシート上の制約あり])になっているだけです。しかし、数値と文字の比較に関して、別途に出てくるというようなので、数値のcountを別々に取りました。そういう仕様で振り分けているのだというしかありません。
もっと複雑なものを想像していましたが、どうやら、その結果は偶然の産物のようです。意図して作られたものではないようです。まだ、修正点はあるかもしれませんが、一応、仕様は分かったような気がします。
興味のある方はどうぞ試してみてください。
'//標準モジュール
'//
Public Function mCountIf(arg1 As Range, arg2 As Variant)
Dim bln As Boolean
Dim fml As String
Dim cnt As Long, cnt2 As Long, cnt3 As Long
Dim expr As String
Dim ope As String
Dim c As Variant
arg2 = Trim(arg2)
Select Case True
Case arg2 Like "=>*"
mCountIf = 0: Exit Function
Case arg2 Like "=<*"
mCountIf = 0: Exit Function
Case arg2 Like ">=*"
ope = ">=": expr = Mid(arg2, 3)
Case arg2 Like "<=*"
ope = "<=": expr = Mid(arg2, 3)
Case arg2 Like "<>*"
ope = "<>": expr = Mid(arg2, 3)
Case arg2 Like ">*"
ope = ">": expr = Mid(arg2, 2)
Case arg2 Like "<*"
ope = "<": expr = Mid(arg2, 2)
Case arg2 Like "=*"
ope = "=": expr = Mid(arg2, 2)
Case Else
ope = "=": expr = arg2
End Select
For Each c In arg1
If VarType(c) = vbString Then
fml = "=""" & c.Value & """" & ope & """" & expr & """"
If Evaluate(fml) Then
cnt = cnt + 1
End If
ElseIf VarType(c) = vbDouble Then
fml = "=""" & c.Value & """" & ope & """" & expr & """"
If Evaluate(fml) Then
cnt2 = cnt2 + 1
End If
Else
cnt3 = 0
End If
Next c
Select Case True
Case VarType(expr) = vbString And expr <> "" And Not IsNumeric(expr)
mCountIf = cnt
Case IsNumeric(expr)
mCountIf = cnt2
Case expr = ""
mCountIf = cnt3
End Select
End Function
'//
誠に申し訳ないのですが、私の知識、理解力では、具体的仕様が理解できていません。
VBAで試す?のを 具体的にどうするのかがわかりません。
mCountIfの関数で、arg1,arg2にいろいろ入れてみただけです。0が返れば≠、1が返れば=のようですが、arg1=123,arg2='123 arg1='123,arg2=123 などでは結果が変わります。
セルの式ではなく、セルの値を評価しているのはわかりました。
セルの値がnullだと(arg1,arg2でも、)、0が返るようです。
文字コード比較ではないから、aAとAaは同値になることもわかりました。
arg2の文字列が”>=文字列”や"<>文字列"のような場合は、比較演算子と文字列に分けて、true,falseの判定をしているというのはわかりました。
大小判定を、何かの方法で、演算子の結果、関数の結果やこのmCountIfの関数のarg1,arg2で、true/falseとやっているから、その結果は、ただExcelシートをながめても、ピンとは来ないというだけのことはわかりました。
その延長線上で、「"<=" & $A$4:$A$8」も、セル位置に合わせ"<=(セル位置のA列のセルの値)"に置換させて、さらに処理しているので、
=mCountIf($I$12:$I$30,"<="&$I$12:$I$30)も計算できるということもわかりました。
arg2に、
① '76のような文字がなく、7、78、789のような数値しかない場合は、通常の文字列とは別系統の文字列として順位評価すること、
② '76のような文字と8のような数値があると、共に数字系の文字列としての順位をつけること、
('76のような文字と8のような数値を文字列とみなした系列としての順位がつく)
③ '88、'32のような文字列だけだと、それらの数字だけの文字列は評価の対象にされないこと、
などが、mCountIf(であって、CountIf(と類似しているらしいことはわかりました。
VBAコードがわからないので、わからないことは前と同じですが、動作の理解は進みました。
文字列、数字列、数値が混在したママで、CountIf(やmCountIf(を使うと、どのように順位が振られるのかのが、おおよそ理解できた気がします。
ありがとうございました。
No.6
- 回答日時:
確かに、No.4の回答のように
1.セル B4 の式 =COUNTIF($A$4:$A$8,"<="&$A$4:$A$8) をドラッグコピーすると
' =COUNTIF($A$4:$A$8,"<="&C4) のドラッグコピーは等しいですね。
配列数式の際にそうしたことが起きるのと似ていると思います。
No.1の回答と回答に対するコメントをやってみると、確かに、何が起きているのかが、私にはわかりません。単純に文字列コードをベースにしているのではなさそうです。(No.4さんのを参考にしました)
No.3の回答は、根気不足だけではなく、内容が難しくて、「★だから、B6に入力した"<=" & $A$4:$A$8という部分は実際は "<=" & $A$6となるのわかる」とは私にはならないです。
文字列と数値のことも、「★最初が要するに最初2文字までに来る文字で、不等号の種類を判別して、それを除いたやつをmaStringに代入して pFormatter(多分nullptrではない)がnullptrでないときは、数値等として解釈可能であるか調べ、解釈可能であったときは、数値比較、それ以外は文字列比較、ということ」というのも理解できないですが、添付画像のように、C12:C26、E12:E26、I12:I26 となることを説明できているのかさえも、私にはわからないです。
No.5
- 回答日時:
こんにちは。
=COUNTIF($A$4:$A$8,"<=" & $A$4:$A$8)
これは、一種の配列計算ですね。どこが配列かというと、"<=" の後は、本来、数字か文字列なのですが、ここに配列になっているわけで、これは、制作側の非公開の隠しコマンドだと思います。マニュアルには載っていませんから。
理由は分かりません、制作側の気まぐれだと思います。
制作上、配列の引数をエラーにしても良かったのではないかと思います。
配列式ではあるのですが、この数式表現は別の配列数式にも書き換えられます。
B4: =SUMPRODUCT(($A$4:$A$8<=$A4)*1) 下にドラッグコピー
添付図をご覧になってください。
仕組みは、
B4:=($A4<=B$3)*1
B5:=($A5<=B$3)*1
= ("hg" <= "hg")*1
=1
= ("hhggfs" <= "hg")*1
=0
となっています。
9行目は、SUM合計で作られています。
たんなる文字の比較ですが、COUNTIF <= は、等しいか、それ以上(文字コード)なら、1と数えることになっています。
なお、必ず、数値 <文字列です。もし、比較するなら、数値を文字列に変えて、文字列と比較しなければなりません。
567 <"123" という等式が成り立ちます。単純な比較する時は、文字列と数値とは混在はできません。
No.4
- 回答日時:
こういう不思議な現象に遭遇した場合の私の常套手段は推理に基づいて実験することです。
推理のネタは文字コードです。
1.式 =$A$4:$A$8 を入力したセル C4 を下方にオートフィル
 ̄ ̄その結果を添付図の列C(橙色)です。
もうお分かりと思うけど、貴方が示したセル B4 の式
=COUNTIF($A$4:$A$8,"<="&$A$4:$A$8)
は
=COUNTIF($A$4:$A$8,"<="&C4)
と同じことで、貴方の添付図に示した他のセルの式もその「同じ」ものをオートフィルしたものに等しいですね。
先を急ぎませう。
2.式 =CODE(MID($A4,COLUMN(A4),1))*1 を入力したセル D4 を右隣および
 ̄ ̄下方にオートフィル(黄色)
3.式 =(D4&TEXT(E4,"000"))*1 を入力したセル F4 を下方にオートフィル(薄
 ̄ ̄青色)
4.式 =COUNTIF(F$4:F$8,"<="&F4) を入力したセル G4 を下方にオートフィ
 ̄ ̄ル(赤地に白抜数値)
私の推理、当たっているかしらン?
以上、此れでも、ゴチャゴチャ講釈は出来るだけ省いたつもり。
No.3
- 回答日時:
部分点狙いの回答。
(【なかなか本題に行かない】)満足してもらえるかわからないが、根気よく読んでもらえれば理解はしてもらえるだろう。
★Excelのソースコードは当然配布されないのでわからないが、LibreOfficeもある程度追従するだろう、ということを飲み込んでもらえると嬉しいなぁ。ここを妥協してもらえないとあと全部無駄になるからなあ
* 逆ポーランド記法を用いた電卓の実装方法
https://knowledge.sakura.ad.jp/220/
これを最後まで読んだ上で。
>高級な言語ではコンパイルといえばもう少し複雑な手法と手順で構文解析を行います。
* 演算子と関数は本来同じもの!シンタックスシュガー。(ただし、言語の文法が中置記法でしか書けないものだったりするだけ)。
オーバーロードの概念がある言語の場合、演算子オーバーロードの説明を読んでおくのも吉。
* BNF記法について
http://www.atmarkit.co.jp/fxml/ddd/ddd004/ddd004 …
** 直接関係ないけど、練習としてJavaの仕様とか見ると面白い。上記BNFがわかっていればそれほど苦労しないはず。
https://docs.oracle.com/javase/specs/jls/se9/htm …
再帰的に定義されている。
StatementExpression(式文) => Assignment(代入) => Expression(式) => AssignmentExpression(代入式)
=> ConditionalExpression 以下略と辿っていくとこんなのにぶち当たる。
15.18. Additive Operators
AdditiveExpression:
MultiplicativeExpression
AdditiveExpression + MultiplicativeExpression
AdditiveExpression - MultiplicativeExpression
15.17. Multiplicative Operators
MultiplicativeExpression:
UnaryExpression
MultiplicativeExpression * UnaryExpression
MultiplicativeExpression / UnaryExpression
MultiplicativeExpression % UnaryExpression
ところで、15.2にはこんな記述がある。
Precedence among operators is managed by a hierarchy of grammar productions. The lowest precedence operator is the arrow of a lambda expression (->), followed by the assignment operators. Thus, all expressions are syntactically included in the LambdaExpression and AssignmentExpression nonterminals:
演算子の優先順位は文法生成規則(BNFや上記Javaの文法で見てきた各定義のことね!)の階層構造による。最も優先度の低い演算子はラムダ式のアロー演算子であり、代入演算子が続く。こういう感じで全ての式は文法上LamdaExressionかAssignmentExpressionの非終端記号に含まれる。
というわけで。【少なくともJavaにおいては、掛け算の方が足し算よりも優先される】のでした。
* 暗黙の型変換
https://asciidwango.github.io/js-primer/basic/im …
* 実際のLibreOfficeの実装は?
ScCompiler関連クラスが主にユーザーが入力した、中置記法を含む式を逆ポーランド記法に変換している。以下例
https://opengrok.libreoffice.org/xref/core/formu …
ScInterpreterクラスが主に逆ポーランド記法になった式(実際にはTokenArray型)を評価している、
練習として余りを求める関数Modを読んでみよう。
【スタックから引数を逆順に取り出していること】を忘れずに。まぁ最初は引数の数を1バイト乗っけてあってGetByte()で取ってるみたいだけど。
ScInterpreter::GetDouble()はスタックの一番上の要素を取り出し、【double型に型変換して返す】。GetString()なんかは、スタックの一番上の要素をStringに変換して返す。GetStackType()なんかは情報見るだけでスタック弄らないみたいだけど。ちなみにScInterpreter::PopString()は型変換しない。欲しい型のデータじゃない場合はエラーになる。
https://opengrok.libreoffice.org/xref/core/sc/so …
そうScInterpreter::ScMod()側で型変換している。結果としてエンドユーザー側からは暗黙の型変換に見える。
本題だ。文字列連結演算子&は、ScInterpreter::ScAmpersand()で当然
ScInterpreter::GetString()を呼んでいる。
https://opengrok.libreoffice.org/xref/core/sc/so …
A1みたいなやつはsvSingleRef,A1:A2みたいなやつはSvDoubleRefって型だ。
ScInterpreter::DoubleRefToPosSingleRef( aRange, aAdr )って奴が呼ばれるみたいだからちょっと定義読んでみようかな。各引数は参照渡しだ。行列(Matrix)周りは全部読み飛ばしてっと。
https://opengrok.libreoffice.org/xref/core/sc/so …
あ、aPosは式を入力したセルで、Tab()はシート番号を返すんだよねー。
★だから、B6に入力した"<=" & $A$4:$A$8という部分は実際は "<=" & $A$6となるのわかるだろうか?同じA列で、4 <= 6 かつ 6 <= 8だからね。いや正直絶対参照か相対参照かはちゃんと調べてなくて自信ないんだけど(汗)
さてこの調子で、エンドユーザー視点の使い方を思い出しながら、ScInterpreter::ScCountIf()も読んでみようか(にっこり)
https://opengrok.libreoffice.org/xref/core/sc/so …
まず最後の引数は条件だったね。
Value(数値等)の場合その値をfValに代入して、bIsStringがfalseになり…
可変長引数絡みでwhileでくくっている部分があるのを臨機応変に解釈。ここはそのままSvDoubleRefを変換せず扱う、っと。
5580行周りで、数値比較であることを確認して5595行あたりの分岐で行列とそれ以外に応じて分岐しているけどどっちにしても要素列挙しながら数え上げているだろうことは同じ。、
最後の引数が文字列だったら…? ScQueryParamBase::FillInExcelSyntaxが呼ばれているな…。
https://opengrok.libreoffice.org/xref/core/sc/so …
copyメソッドは、文字列の一部を取ってくるメソッドとして読むと…
★最初が要するに最初2文字までに来る文字で、不等号の種類を判別して、それを除いたやつをmaStringに代入して
pFormatter(多分nullptrではない)がnullptrでないときは、数値等として解釈可能であるか調べ、解釈可能であったときは、数値比較、それ以外は文字列比較、ということだ。
だから例えば、
=COUNTIF(A1:A2,">3")
は数値3との比較だが、B1に3が入っていたとして
=COUNTIF(A1:A2,">B1")であったときには
"B1"という文字列との比較になる、ということだ。
★手元のLibreOfficeの環境だと
=COUNTIF(A1:A2,">2017-01-01")は日付=>数値比較になったりする。面倒くさいから調査してないだけだが、「どんな文字列が数値比較になるか」をちゃんと把握しておく必要がありそう。
注意事項は★に記しておいた。ちゃんと把握するのはそれ自体難しい。
No.2
- 回答日時:
No.1です。
>データはA$3:A$20 (文字のセルと、数値のセルの混在です)
>しかし、順位は正しくないです。 異なる値に同順位がでます。
具体的にどのようなデータが入っているのか判らないのですが、
文字コードが基準になっていると思います。
ただ気を付けなければならないのは
「文字列」セルと「数値セル」が混在している場合は思ったような並び替えができないことがあります。
私にはサイトで検索してもその原因ははっきり判りません。
前回投降した数式は文字列の並び替えより数値セル(RANK関数)の同順位を回避するために使うコトがほとんどです。
(文字列の並び替えで使ったコトはないと思います)
↓のサイトが参考にならないでしょうか?
http://officetanaka.net/excel/function/tips/tips …
的確な回答でなくてごめんなさい。m(_ _)m
No.1
- 回答日時:
こんばんは!
個人的にそのような使い方をしたことはありませんが、
お示しの使い方は少し裏技的な使い方になります。
式の説明となると当方もなぜそうなるかは、はっきり説明できません。
仮に一気に別列に小さい順(昇順)に表示する場合
=INDEX(A$4:A$8,MATCH(ROW(A1),INDEX(COUNTIF(A$4:A$8,"<="&A$4:A$8),),))
という数式を入れフィルハンドルで下へコピーすると
お示しの画像のB列の昇順にA列データが表示されるはずです。
自分であれば、単に順位付けだけならそんな難しい使い方をせず
B4セルに
=COUNTIF(A$4:A$8,"<="&A4)
という数式を入れ下へフィル&コピーします。
(数値データのRANK関数と同じコトですかね)
※ 仮に同順位(重複データ)があり、順位の差をつけたい場合は
数値データでもRANK関数を使わず
=COUNTIF(A$4:A$8,"<"&A4)+COUNTIF(A$4:A4,A4)
という数式を入れフィル&コピーで同順位なしの順位が返ります。
(同順位の場合は上側のデータが上位となる)
尚、降順の場合は不等号の向きを変えます。
※ 式の説明ではなく、当方個人的な使い方だけでごめんなさい。m(_ _)m
回答ありがとうございます。
画像を貼り付けられないのですが、次の式を入れて見ました。
データはA$3:A$20 (文字のセルと、数値のセルの混在です)
しかし、順位は正しくないです。 異なる値に同順位がでます。
式はD3のセルに =COUNTIF(A$3:A$20,"<"&A3)+COUNTIF(A$3:A4,A3) (フィルコピー)
並べ替えもおかしいです。 出てこない(抜けてしまう)データが多発します。
式はC3のセルに =INDEX(A$3:A$20,MATCH(ROW(A1),INDEX(COUNTIF(A$3:A$20,"<="&A$3:A$20),),)) (フィルコピー)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) エクセルの数式について教えてください。 2 2023/03/04 09:54
- Excel(エクセル) エクセルの数式について教えてください。 2 2023/02/18 11:30
- Excel(エクセル) 【エクセル】COUNTIFの検索条件が可変する数字の場合の数式 1 2022/09/27 15:34
- Visual Basic(VBA) エクセルマクロでアニメを作る方法を教えてください。 1 2023/02/07 14:27
- Excel(エクセル) 表示形式、文字列セル(列)に数式を入力するには マクロ 1 2022/09/18 10:53
- Excel(エクセル) エクセルのマクロについて教えてください。 2 2023/02/11 14:50
- Excel(エクセル) 出勤簿の土、日、休日に色付けできない 2 2022/08/04 20:10
- Excel(エクセル) エクセル 関数について質問です。 2 2022/10/03 11:14
- Excel(エクセル) Countifよりも早く重複数をカウントする方法ありますか? 18 2022/07/04 13:39
- Excel(エクセル) countif関数について質問 4 2022/06/14 12:11
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
エクセル初心者です 関数の入れ...
-
【関数】先頭だけにある、半角...
-
エクセル 白黒印刷で白線を印刷...
-
Excelのチェックボックスの使い...
-
【関数】適切な文字数の数字を...
-
Excelのpivotについて質問です
-
Excel ピボットテーブルで日付...
-
LOOKUP関数を使えばいいのでし...
-
エクセル関数を教えてください
-
エクセルのセルに同じ大きさの...
-
UNIQUE関数が使えないバージョ...
-
excelの不要な行の削除ができな...
-
エクセルで「-0.0」と表示さ...
-
時間によってファイル名が変わ...
-
WPS OFFICEでの縦書きについて
-
エクセルの関数について教えて...
-
Aというブックの1というシート...
-
【マクロ】シート名を取得する...
-
VBA Private Sub Worksheet_Cha...
-
VBA、Excelのworkbook.open に...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Excel 2019 のピボットテーブル...
-
[関数得意な方]教えて下さい・...
-
Excelにてある膨大なデータを管...
-
[関数について]わかる方教えて...
-
Excel初心者です。 詳しい方、...
-
excelの不要な行の削除ができな...
-
エクセル関数に詳しい方教えて...
-
INDIRECTを使わず excelで複数...
-
[オートフィルタ]で抽出された...
-
エクセルの神よ、ご回答を! エ...
-
エクセル関数に詳しい方、教え...
-
各ページの1番上の表示について
-
Excelで写真のような表を作った...
-
エクセルで不等号記号(≠)が上に...
-
数学 Tan(θ)-1/Cos(θ)について...
-
Excel 2019 は、SPILL機能があ...
-
Excelで全角を半角にしたいので...
-
条件付き書式を教えてください
-
Excel フィルターを掛けた状態...
-
[オートフィルタ]の適用範囲の...
おすすめ情報