プロが教える店舗&オフィスのセキュリティ対策術

C#の初心者です。

以下のようなXML形式のデータがあります。
sample.txtという名前でCドライブ直下に保存してあります。

<resultset>
<result>
<title>123456789</title>
<id>{4E55D112-0048-E011-BC1D-00155D026322}</id>
<fullname>日本太郎</fullname>
<fullnamekana>ニホンタロウ</fullnamekana>
</result>
<result>
<title>123456789</title>
<id>{4E55D112-0048-E011-BC1D-00155D026322}</id>
<fullname>日本次郎</fullname>
<fullnamekana>ニホンジロウ</fullnamekana>
  <telephone>000-0000-1111</telephone>
</result>
<result>
<title>123456789</title>
<id>{4E55D112-0048-E011-BC1D-00155D026322}</id>
<fullname>日本三郎</fullname>
<fullnamekana>ニホンサブロウ</fullnamekana>
</result>
</resultset>

御覧の通り、resultset要素の中にresult要素が3つあります。
しかしながらresult要素の中にあるいくつかの要素の数は可変です。
この例では、1番目と3番目のresult要素の中の要素はまったく同じものですが、2番目のresultの中の要素はtelephoneという他のresult要素内にはない要素が存在します。
私はこの3つのresult要素の中から、最大の要素数を含むresult要素のみを取得したいと思っております。
この例では、2番目のresult要素が一番たくさん要素を含んでいるので(telephone分)、希望結果は以下のような感じです。

<result>
<title>123456789</title>
<id>{4E55D112-0048-E011-BC1D-00155D026322}</id>
<fullname>日本次郎</fullname>
<fullnamekana>ニホンジロウ</fullnamekana>
  <telephone>000-0000-1111</telephone>
</result>

これを実現するため、私は以下のようなコードを考えました。
(頭が悪いので、かなり時間がかかりました・・・)

StreamReader sample = new StreamReader(@"C:\sample.txt");
var XmlResult = XElement.Parse(sample.ReadToEnd());

var resultElementsMaxValue = (
from result in XmlResult.Elements("result")
select new { resultElementsCounts = result.Elements().Count() }
).Max(c => c.resultElementsCounts);

var modelResult = from result in XmlResult.Elements("result")
where result.Elements().Count().Equals(resultElementsMaxValue)
select result;


しかしながら、この方法では、result内要素数の一度MAX値を取得した後、そのMAX値で再度、MAX値と同じ数の要素を含むresult要素を検索しております。
これは効率が悪い気がします。
MAX値を取得したときと同じタイミングで、そのresult要素を取得する方法はないのでしょうか。

ご教授、よろしくお願いします。

A 回答 (2件)

あ、ANo.1だと複数要素を返さないですね。


複数返すようにすると、こうかな:

var rs = XmlResult.Elements( "result" ).Select( it => new { n = it.Elements().Count(), v = it } ).ToArray();
var resultElementsMaxValue = rs.Max( it => it.n );
var modelResult = rs.Where( it => it.n == resultElementsMaxValue ).Select( it => it.v );

質問文のとあんまり変わらないので、あえて1回ですますものとして、こうとか:

var resultset = XmlResult.Elements( "result" );
var num_result= resultset.Count();
var rs = new XElement[ num_result ];
int num_rs = 0, max_num_elem_result = -1;
foreach ( var result in resultset ){
int num_elem_result = result.Elements().Count();
if ( num_elem_result < max_num_elem_result ){ continue; }
if ( num_elem_result > max_num_elem_result ){ num_rs = 0; max_num_elem_result = num_elem_result; }
rs[ num_rs++ ] = result;
}
Array.Resize( ref rs, num_rs );
foreach ( var result in rs ){ System.Console.WriteLine( result ); }

全然LINQじゃなくなってますが。
    • good
    • 0
この回答へのお礼

osamuy様

ありがとうございます。
その方法で実現できそうです。

お礼日時:2011/03/22 18:59

ググってみた感じだと、こんなのとか:



var r1 = ( from result in XmlResult.Elements( "result" )
select new { n = result.Elements().Count(), v = result }
).Aggregate( (reg, it) => it.n > reg.n ? it : reg ).v;
System.Console.WriteLine( r1 );

でも、こっちのほうが効率的かもしれない:

int max_nelem = -1; XElement r2 = null;
foreach ( var it in XmlResult.Elements( "result" ) ){
int c = it.Elements().Count();
if ( c > max_nelem ){ max_nelem = c; r2 = it; }
}
System.Console.WriteLine( r2 );
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!