2017-03-20 7 views
-1

私は、惑星とその月を含むコレクションを子コレクションとして持っています。
コレクションですが、実際はツリーのような構造を表しています。私は簡単に2つのツリーレベルしか表示していませんが、各惑星や月にはさらに化学元素の集合が存在する可能性があるので、単純化のために2レベルのツリーを使用します。ラムダ式(または他の方法)でコレクションを検索する

Mercury 

Venus 

Mars 
    - Deimos 
    - Phobos 

Jupiter 
    - Europa 
    - Ganymede 
    - Io 

私はちょうど私がその名前に「M」を含む各項目に対して、このリストを検索したい

var myList = myCollection.Values.ToList(); 

を使用し、リストにこのコレクションを変換する方法を知っています。親の名前に "m"がなくて子どもの月がある場合、その子(月)とその親(惑星)を含めたいと思います。木星の場合、私は木星とガニメデの両方を私のリストに入れます。

ため、以下のリストを返すだろう「M」のための私の検索

{水星、火星、ダイモス、木星、ガニメデ}

同上このため、ラムダを使用して好むが、そうする必要はありません

UPDATE:構造

BodyNode 
-ID  [Guid] 
-Name [string] 
-IsChild [bool] 
-Parent [BodyNode] 
-Children[BodyList ObservableCollection of BodyNode] 

BodyTreeNode : BodyNode 
-Expanded [bool] 
-Selected [bool] 
-Enabled [bool] 
+0

ツリーを検索するのに 'DFS'を使用し、名前に 'm'が含まれている場合はリストに追加します。 – dcg

+0

大文字小文字を区別しない比較を行う場合は、['node.Name.IndexOf(" m "、StringComparison.OrdinalIgnoreCase)> -1']を使用してください。(https://msdn.microsoft.com/en-us/library/ms224425 ToUpper/ToLowerと['Contains']の組み合わせ(https://msdn.microsoft.com/en-us/library/dy85x1sa(v = 1.10%))の代わりに、 vs.110).aspx)を参照してください。 'public static bool(この文字列のソース、文字列の値、StringComparisonの比較)=> source.IndexOf(値、比較)> -1;'忘れずに拡張メソッドを作ることができます。引数の検証。 – Johnbot

答えて

1
var MRecords = myList.Where(x=>x.toUpper().Contains("M")); 

var result = new HashSet<"yourClass">(); //i didn`t use hashset before but this as stated in [here](http://stackoverflow.com/questions/6391738/what-is-the-difference-between-hashsett-and-listt) eliminates duplicates 

foreach(var record in MRecords) 
{ 
    result.Add(record); 
    var ParentLooper = record; 
    while(ParentLooper.parent!=null) //i suppose roots have the parent as null 
    { 
     result.add(ParentLooper.parent); 
     ParentLooper = ParentLooper.parent; 
    } 
} 
return result; 
+0

リンクはhttp://stackoverflow.com/questions/6391738/what-is-the-difference-between-hashsett-and-listt –

+0

ありがとう、しかし、これはどのように子供が "M" "これは、これには "M"を含むすべてのitesm(親と子供)が含まれているように見えます。これはMRecordsに含まれるものです。 – pixel

+0

申し訳ありませんコミュニティのxDのために速く入力しましたが、結果はMRecordsではありません –

2

あなたはあなたのデータはツリー状の構造であることを本当に確信しているなら、あなたはCYCをチェックせず(のような何かを行うことができますレ):

bool GetNodes(Tree root, List<Tree> result, Func<Tree, bool> f) { 
    bool add = f(root); 
    foreach (var child in root.Children) { 
     add ||= GetNodes(child, result, f); 
    } 
    if (add) 
      result.Add(root); 
    return add; 
} 

fあなたがツリーを追加するかどうかを知らせる機能です。例えば。 (t)=>t.Name.Contains("m")

編集:

var r = new List<Base>(); 
myList.Foreach(o => GetNodes(o, r, (b) => b.Name.Contains("m")); 
+0

ありがとうございますが、私はそれに従うことに苦労しています。また、私はTree型を持っていない、私はリストに変換するコレクションがあります。 – pixel

+0

すべてのオブジェクトには、子を表す 'List'がありますか?彼らは基本クラスから派生していますか? – dcg

+0

私の編集を見て、それがあなたに適しているかどうか教えてください。 – dcg

0

:あなたはその後、としてそれを使用することになり

bool GetNodes(Base b, List<Base> result, Func<Base, bool> f) { 
    bool add = f(b); 
    foreach (var child in b.GetChildren) { 
      add ||= GetNodes(child); 
    } 
    if (add) result.Add(b); 
    return add; 
} 

:すべてのオブジェクトは、基地から派生し、基本プロパティを持っているpublic List<Base> GetChildren{get;}上記のロジックは次のように実装することができと仮定すると、個人的には、objectsには、このようなツリーエンティティを扱うときに独自のカスタムクラスのIEnumerablesが含まれていることをお勧めします。あなたのPlanetとあなたの月はどちらも同じプロパティを持っているので、それらは基本的にクラスPlanetの両方です。

private class Planet 
     { 
      public string Name { get; set; } = string.Empty; 
      public IEnumerable<Planet> Children { get; set; } = new List<Planet>(); 
     } 

これは、ラムダの使用が少し簡単になります:私たちは名前だけを扱っていることを考えると、私は以下のように民間のモックアップクラスを作りました。私はこの1つをテストするために取得していないが、それは、それはそれに近いですし、そこにあなたを取得する必要があります修正しない場合:

 IEnumerable<Planet> myCollection = new List<Planet>(); 
     myCollection = LetThereBeLight(true); //method to populate the list 
     var myList = myCollection.ToList().Where(t => t.Name.ToUpper().Contains("M")); 
     myList.ToList().AddRange 
          (
          myCollection.SelectMany(t => t.Children.Where 
            (
             v => v.Name.ToUpper().Contains("M")).Distinct() 
            ) 
          ); 

あなたはそれをすべて1ラムダ作ることができますが、それはスクイズにしようとせず読み十分に懸命ですそれはすべて1行になります。 という名前に " - "を追加するなど、月の違いを表したい場合は、それぞれPlanet'sChildrenコレクションをループすることができます。ここでは複製が完全に可能であるため、myList.Distinct()のみを使用してください。

+0

ですが、上記のmyListには「M」の項目のみが含まれています。もし惑星が "M"を持っておらず、その月だけが "M"を持っていたら?それらは両方とも含まれていなければなりません(すなわち、木星と月のガニメデ)。私はそれを含めて上記を見ません。それとも私は何かが足りない? – pixel

+0

おっと、そうです、私の例はあなたにすべての "M"クラスの惑星とすべての "M"クラスの月を与えます(申し訳ありませんが、冗談はそこにありました。改訂中... – CDove

2

コレクションのすべての要素のシーケンスがあるとします。その後、Where、または他のシーケンス演算子をそのシーケンスで使用できます。だからあなたの最善の策は、そのシーケンスを構築することです:

static class Extensions { 
public static IEnumerable<Nodes> Flatten(this IEnumerable<Node> nodes) 
{ 
    foreach(var node in nodes) 
    { 
    yield return node; 
    foreach (var child in node.Children.Flatten()) 
     yield return child; 
    } 
} 
} 

Easy peasy。そして今、あなたは簡単に言うことができる:

var results = from node in myCollection.Values.Flatten() 
       where node.Name.ToLower().Contains("m") 
       select node; 
は、名前にM持つすべての要素のリストです

またはラムダ

var results = myCollection.Values.Flatten() 
    .Where(node => ... and so on ...); 

を使用しては、何をしたいことはあります名前の中にmを持つ要素や子が持つすべての要素のリストだからそれを書いてください。私たちに必要なすべてのツールがあります!

var results = from node in myCollection.Values.Flatten() 
       where node.Name.Contains("m") || node.Children.Flatten().Any(node.Name.Contains("m")) 
       select node; 

ここでは、これはむしろ非効率的です。理由は分かりますか? - それはトリックです。そして今、実際に必要な場合に、分析してより効率的になるように働く何かがあります。

+0

私は「フラットン」についても考えなかった。結果に親子関係を保持する必要がない場合は、これが方法です。 – CDove

関連する問題