2017-04-16 15 views
3

私はこの問題を一週間一回解決しようと努力してきました。この時点で、C#言語をさらに深く浸透させることなく解決できるかどうかは疑問です。 CSVファイルを使って作業し、並べ替えて整理するだけでなく、C#の初心者でもかなり新しくなっています。CSVファイルを使って作業する

私はCSVファイルをアルファベット順にソートしようとしています。非表示にする必要がある項目を隠し、親、子、孫の要素に基づいて深度レベルを持っています。

私はそれらのいくつかでうまくいっていて、多少の作業コードを書いていますが、それらをアルファベット順に並べ替える方法と、それらが属している親と子に基づいて適切な深度レイヤを与える方法はわかりません。ここで

は私が整理しようとしてきたモックアップのCSVです:私はセミコロンで項目を区切られてきた

ID;MenuName;ParentID;isHidden;LinkURL 
1;Company;NULL;False;/company 
2;About Us;1;False;/company/aboutus 
3;Mission;1;False;/company/mission 
4;Team;2;False;/company/aboutus/team 
5;Client 2;10;False;/references/client2 
6;Client 1;10;False;/references/client1 
7;Client 4;10;True;/references/client4 
8;Client 5;10;True;/references/client5 
10;References;NULL;False;/references 

、私は表示する必要がある項目を表示しましたが、私はに失敗します私のようにそれらを並べ替える。

ソートは次のようになります。私はそれらを並べ替えるか、スラッシュが、どのようなコードが再現するのインデックスを取得することにより、その順序でそれらを表示しようとした

Company 
    About Us 
    Team 
    Mission 
References 
    Client 1 
    Client 2 

はどのようにすべきではありません表示され、そして、それは次のようになります。

Company 
    About Us 
    Mission 
    Team 
    Client 2 
    Client 1 
References 

を私は再帰的にidを持つ親IDと一致し、他の試みでは、コンソールの表示は次のようになります。

Company 
    About Us 
    Mission 
    Team 
     Client 2 
     Client 1 
References 

私は友人とこれを解決しようとしましたが、このコードは別の親IDを使用する別のファイルでも機能するので、彼はこの問題にどのようにアプローチするのかわかりません。このすべての上に

のみ0のインデックスやインデックスがありますので、私は、配列のインデックス彼らすることができません彼らの手紙に基づくか、私は1

のインデックス位置を入力すると、コンソールがクラッシュしていますここで

が、私はそれらを並べ替えることができない最初の部分のコードです:

class Program 
{ 
    static void Main(string[] args) 
    { 
     StreamReader sr = new StreamReader(@"Navigation.csv"); 
     string data = sr.ReadLine(); 

     while (data != null) 
     { 
      string[] rows = data.Split(';'); 
      int id; 
      int parentId; 
      bool ids = Int32.TryParse(rows[0], out id); 
      string name = rows[1]; 
      bool pIds = Int32.TryParse(rows[2], out parentId); 
      string isHidden = rows[3]; 
      string linkUrl = rows[4]; 
      string[] splitted = linkUrl.Split('/'); 

      if (isHidden == "False") 
      { 
       List<CsvParentChild> pIdCid = new List<CsvParentChild>() 
       { 
        new CsvParentChild(id, parentId, name, linkUrl) 
       }; 
      } 

      data = sr.ReadLine(); 
     } 
    } 
} 

class CsvParentChild 
{ 

    public int Id; 
    public int ParentId; 
    public string Name; 
    public string LinkUrl; 
    public List<CsvParentChild> Children = new List<CsvParentChild>(); 

    public CsvParentChild(int id, int parentId, string name, string linkUrl) 
    { 

     Id = id; 
     ParentId = parentId; 
     Name = name; 
     LinkUrl = linkUrl; 
     string[] splitted = linkUrl.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); 

     if (splitted.Length == 1) 
     { 
      Console.WriteLine($". { name }"); 
     } 
     else if (splitted.Length == 2) 
     { 
      Console.WriteLine($".... { name }"); 
     } 
     else if (splitted.Length == 3) 
     { 
      Console.WriteLine($"....... { name }"); 
     } 
    } 
} 

そしてここでは、第二部のためです:

class Program 
{ 
    static void Main(string[] args) 
    { 
     // Get the path for the file 
     const string filePath = @"../../Navigation.csv"; 

     // Read the file 
     StreamReader sr = new StreamReader(File.OpenRead(filePath)); 
     string data = sr.ReadLine(); 

     while (data != null) 
     { 

      string[] rows = data.Split(';'); 

      ListItems lis = new ListItems(); 

      int id; 
      int parentId; 

      // Get the rows/columns from the Csv file 
      bool ids = Int32.TryParse(rows[0], out id); 
      string name = rows[1]; 
      bool parentIds = Int32.TryParse(rows[2], out parentId); 
      string isHidden = rows[3]; 
      string linkUrl = rows[4]; 

      // Split the linkUrl so that we get the position of the 
      // elements based on their slash 
      string [] splitted = linkUrl.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); 

      // If item.isHidden == "False" 
      // then display the all items whose state is set to false. 
      // If the item.isHidden == "True", then display the item 
      // whose state is set to true. 
      if (isHidden == "False") 
      { 
       // Set the items 
       ListItems.data = new List<ListItems>() 
       { 
        new ListItems() { Id = id, Name = name, ParentId = parentId }, 
       }; 

       // Make a new instance of ListItems() 
       ListItems listItems = new ListItems(); 

       // Loop through the CSV data 
       for (var i = 0; i < data.Count(); i++) 
       { 
        if (splitted.Length == 1) 
        { 
         listItems.ListThroughItems(i, i); 
        } 
        else if (splitted.Length == 2) 
        { 
         listItems.ListThroughItems(i, i); 
        } 
        else 
        { 
         listItems.ListThroughItems(i, i); 
        } 
       } 
      } 

      // Break out of infinite loop 
      data = sr.ReadLine(); 
     } 
    } 

public class ListItems 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
     public int ParentId { get; set; } 
     public static List<ListItems> data = null; 
     public List<ListItems> Children = new List<ListItems>(); 

     // http://stackoverflow.com/a/36250045/7826856 
     public void ListThroughItems(int id, int level) 
     { 
      Id = id; 

      // Match the parent id with the id 
      List<ListItems> children = data 
       .Where(p => p.ParentId == id) 
       .ToList(); 

      foreach (ListItems child in children) 
      { 
       string depth = new string('.', level * 4); 
       Console.WriteLine($".{ depth } { child.Name }"); 
       ListThroughItems(child.Id, level + 1); 
      } 
     } 
    } 
} 
+0

本当にCSVを使用する必要がありますか? CSVは、運動の場合を除いて、これのために非常に貧しい選択と思われます。 XML、JSON、またはYAMLなどのよくサポートされたライブラリを持つ階層的なマークアップ言語は、はるかに優れた選択肢のように聞こえる。もう1つの選択肢は、ある種のSQLデータベースに入れて、SQLを使ってソートし、それを既にソートしてエクスポートすることです。あなたはSQLiteを使うことができます。 –

+0

私は問題を解決しようとするインターンシップのインタビューのため、私は主にフロントエンドのポジションに集中しているので、ファイルをソートするように求められます(そして、CSVを使用してソリューションをテストしています)。数日前、PluralsightからC#を学び始めたので、私はそれをソートするのに失敗しました。私はまだ中間コースに到達していません。そして、これは私に可能な解決策を試してみる時間です。 そして、C#で解決するように求められています。 – Timathy

+0

ああ。私は完全に理解する。 –

答えて

1

各項目について、あなたはSOR」のようなものを構築する必要がありますt個の配列で構成されています。ソート配列は、項目の祖先のIDから最も遠い順に並べられています。 "Team"のソート配列は[1, 2, 4]です。ここで

は、各アイテムのソート配列です:

[1] 
[1, 2] 
[1, 3] 
[1, 2, 4] 
[10, 5] 
[10, 6] 
[10, 7] 
[10, 8] 
[10] 

あなたがこれをしたら、アイテムをソートすることは簡単です。 2つの「並べ替え配列」を比較する場合は、各配列の順番に並べ替えます。それらが異なる場合は、最初の数字の値に応じてソートすれば完了です。それらが同じ場合は、2番目の番号を見てください。 2番目の数字がない場合は、配列の長さでソートします。つまり、何も何も前に来ません。このアルゴリズムを適用する

は、我々が得る:その後

[1] 
[1, 2] 
[1, 2, 4] 
[1, 3] 
[10] 
[10, 5] 
[10, 6] 
[10, 7] 
[10, 8] 

を、フラグに基づいて項目を非表示にします。それはとても簡単なので私はあなたにそれを残します。深さは簡単です:ソート配列の長さです。

+1

ありがとう、私は今これについてどのように大まかな考えを持っていると思う、ありがとう。 :) – Timathy

1

私のアプリケーションをコンパイルし、データを次の出力を生成した。

Company 
     About Us 
       Team 
     Mission 
References 
     Client 1 
     Client 2 
     Client 4 
     Client 5 

私は構造のようなあなたのツリーを作成するために、オブジェクトの関係を使用しようとするでしょう。 質問の主な難点は、親が問題ではないということです。子供たちはそうです。 コード内のある時点で、階層を逆にする必要があります。最初に子どもを解析するが、最初に親を読んで出力を作成する。

私たちのツリーのルーツは、親なしのデータエントリです。これはかなり自明である必要があり

の解析

は、我々は、入力配列を解析し、それのプロパティにデータを格納するコンストラクタで素敵なクラスを持っています。 すべての行をリストに格納します。これでやった後、リストを変換しましたが、並べ替えはまったく起こりませんでした。

public partial class csvRow 
{ 
    // Your Data 
    public int Id { get; private set; } 
    public string MenuName { get; private set; } 
    public int? ParentId { get; private set; } 
    public bool isHidden { get; private set; } 
    public string LinkURL { get; private set; } 

    public csvRow(string[] arr) 
    { 
     Id = Int32.Parse(arr[0]); 
     MenuName = arr[1]; 
     //Parent Id can be null! 
     ParentId = ToNullableInt(arr[2]); 
     isHidden = bool.Parse(arr[3]); 
     LinkURL = arr[4]; 
    } 
    private static int? ToNullableInt(string s) 
    { 
     int i; 
     if (int.TryParse(s, out i)) 
      return i; 
     else 
      return null; 
    } 
} 
static void Main(string[] args) 
{ 
    List<csvRow> unsortedRows = new List<csvRow>(); 
    // Read the file 
    const string filePath = @"Navigation.csv"; 
    StreamReader sr = new StreamReader(File.OpenRead(filePath)); 
    string data = sr.ReadLine(); 
    //Read each line 
    while (data != null) 
    { 
     var dataSplit = data.Split(';'); 
     //We need to avoid parsing the first line. 
     if (dataSplit[0] != "ID") 
     { 
      csvRow lis = new csvRow(dataSplit); 
      unsortedRows.Add(lis); 
     } 
     // Break out of infinite loop 
     data = sr.ReadLine(); 
     } 
     sr.Dispose(); 

     //At this point we got our data in our List<csvRow> unsortedRows 
     //It's parsed nicely. But we still need to sort it. 
     //So let's get ourselves the root values. Those are the data entries that don't have a parent. 
     //Please Note that the main method continues afterwards. 

私達の木Struktureを作成し、私たちは、子供たちとそれらをソート返すパブリックChildrenSortedプロパティを定義することで、起動項目

の並べ替え。これは実際には私たちがやっているすべての並べ替えであり、再帰的に作業するよりも並べ替えが簡単です。

子を追加する関数も必要です。入力をかなりフィルタリングし、row.parentId = this.IDのすべての行を検索します。

最後のものは、出力を定義し、コンソールに印刷できるものを得ることができる関数です。

public partial class csvRow 
{ 
    private List<csvRow> children = new List<csvRow>(); 
    public List<csvRow> ChildrenSorted 
    { 
     get 
     { 
      // This is a quite neet way of sorting, isn't it? 
      //Btw this is all the sorting we are doing, recursion for win! 
      return children.OrderBy(row => row.MenuName).ToList(); 
     } 
    } 

    public void addChildrenFrom(List<csvRow> unsortedRows) 
    { 
     // Add's only rows where this is the parent. 
     this.children.AddRange(unsortedRows.Where(
      //Avoid running into null errors 
      row => row.ParentId.HasValue && 
      //Find actualy children 
      row.ParentId == this.Id && 
      //Avoid adding a child twice. This shouldn't be a problem with your data, 
      //but why not be careful? 
      !this.children.Any(child => child.Id == row.Id))); 


     //And this is where the magic happens. We are doing this recursively. 
     foreach (csvRow child in this.children) 
     { 
      child.addChildrenFrom(unsortedRows); 
     } 
    } 

    //Depending on your use case this function should be replaced with something 
    //that actually makes sense for your business logic, it's an example on 
    //how to read from a recursiv structure. 
    public List<string> FamilyTree 
    { 
     get 
     { 
      List<string> myFamily = new List<string>(); 
      myFamily.Add(this.MenuName); 
      //Merges the Trees with itself as root. 
      foreach (csvRow child in this.ChildrenSorted) 
      { 
       foreach (string familyMember in child.FamilyTree) 
       { 
        //Adds a tab for all children, grandchildren etc. 
        myFamily.Add("\t" + familyMember); 
       } 
      } 
      return myFamily; 
     } 
    } 
} 

ツリーに項目を追加し、これが私達が実際に私たちのデータを扱う私の主な機能、の2番目の部分です彼らに

にアクセスする(右後sr.Dispose();)

var roots = unsortedRows.Where(row => row.ParentId.HasValue == false). 
     OrderBy(root => root.MenuName).ToList(); 

    foreach (csvRow root in roots) 
    { 
     root.addChildrenFrom(unsortedRows); 
    } 

    foreach (csvRow root in roots) 
    { 
     foreach (string FamilyMember in root.FamilyTree) 
     { 
      Console.WriteLine(FamilyMember); 
     } 
    } 
    Console.Read(); 
} 

ソースコード全体(Visual StudioのC#コンソールアプリケーション)

これを使用して、再帰構造のテスト、再生、および詳細を確認できます。

著作権2017エルダーKersebaum

Apacheライセンスの下でライセンス、バージョン2.0(以下 "ライセンス")。 ライセンスに従わない限り、このファイルを使用することはできません。適用される法律または書面での同意がない限り あなたは

http://www.apache.org/licenses/LICENSE-2.0 

でライセンスのコピーを入手することができる、ライセンスの下で配布されたソフトウェア は、保証または条件なし 、「現状のまま」配布され明示的にも黙示的にも、いかなる種類のものでもありません。 ライセンスに関する特定の言語のライセンス、およびライセンスに基づく制限については、 の制限を参照してください。

using System; 
using System.IO; 
using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleApplication49 
    { 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<csvRow> unsortedRows = new List<csvRow>(); 
      const string filePath = @"Navigation.csv"; 
      StreamReader sr = new StreamReader(File.OpenRead(filePath)); 
      string data = sr.ReadLine(); 
      while (data != null) 
      { 
       var dataSplit = data.Split(';'); 
       //We need to avoid parsing the first line. 
       if (dataSplit[0] != "ID") 
       { 
        csvRow lis = new csvRow(dataSplit); 
        unsortedRows.Add(lis); 
       } 
       // Break out of infinite loop 
       data = sr.ReadLine(); 
      } 
      sr.Dispose(); 
      var roots = unsortedRows.Where(row => row.ParentId.HasValue == false). 
       OrderBy(root => root.MenuName).ToList(); 

      foreach (csvRow root in roots) 
      { 
       root.addChildrenFrom(unsortedRows); 
      } 

      foreach (csvRow root in roots) 
      { 
       foreach (string FamilyMember in root.FamilyTree) 
       { 
        Console.WriteLine(FamilyMember); 
       } 
      } 
      Console.Read(); 
     } 
    } 
    public partial class csvRow 
    { 
     // Your Data 
     public int Id { get; private set; } 
     public string MenuName { get; private set; } 
     public int? ParentId { get; private set; } 
     public bool isHidden { get; private set; } 
     public string LinkURL { get; private set; } 

     public csvRow(string[] arr) 
     { 
      Id = Int32.Parse(arr[0]); 
      MenuName = arr[1]; 
      ParentId = ToNullableInt(arr[2]); 
      isHidden = bool.Parse(arr[3]); 
      LinkURL = arr[4]; 
     } 
     private static int? ToNullableInt(string s) 
     { 
      int i; 
      if (int.TryParse(s, out i)) 
       return i; 
      else 
       return null; 
     } 
     private List<csvRow> children = new List<csvRow>(); 
     public List<csvRow> ChildrenSorted 
     { 
      get 
      { 
       return children.OrderBy(row => row.MenuName).ToList(); 
      } 
     } 
     public void addChildrenFrom(List<csvRow> unsortedRows) 
     { 
      this.children.AddRange(unsortedRows.Where(
       row => row.ParentId.HasValue && 
       row.ParentId == this.Id && 
       !this.children.Any(child => child.Id == row.Id))); 
      foreach (csvRow child in this.children) 
      { 
       child.addChildrenFrom(unsortedRows); 
      } 
     } 
     public List<string> FamilyTree 
     { 
      get 
      { 
       List<string> myFamily = new List<string>(); 
       myFamily.Add(this.MenuName); 
       foreach (csvRow child in this.ChildrenSorted) 
       { 
        foreach (string familyMember in child.FamilyTree) 
        { 
         myFamily.Add("\t" + familyMember); 
        } 
       } 
       return myFamily; 
      } 
     } 
    } 
}