2014-01-31 87 views
0

構建字符串我有放在特定索引值,像這樣的數組:遞歸從數組

{4: 6, 8: 1} 

它有時可有在它裏面陣列。我有一個函數可以從頭開始構建一個字符串,因爲將數組轉換爲字符串會將所有沒有值的索引放入該字符串中,有時索引可能會達到數百萬。

請注意,GetValue是一個單獨的函數並返回一個對象,而DatabaseArray只是Player.IO使用的一種特殊類型的數組。我還會指出,我不會簡單地使用foreach,因爲我需要顯示索引。

value = "{"; 
DatabaseArray copiedarray = (DatabaseArray)result.GetValue(i); 
for (int j = 0; j < copiedarray.Count; j++) 
{ 
    if (copiedarray.Contains(j)) 
    { 
     if (value != "{") 
     { 
      value = value + ", "; 
     } 
     value = value + j + ": " + copiedarray.GetValue(j).ToString(); 
    } 
} 
value = value + "}"; 

這適用於頂層,但不適用於任何底層數組。它會變成這樣:

{0: <null>, 1: <null>, 2: <null>, 3: {0: <null>, 1: 2}, 4: 5} 

進入這個:

{3: {0: <null>, 1: 2}, 4: 5} 

但我想讓它這樣的:

{3: {1: 2}, 4: 5} 

我不能找到一種方法,使其重申通過與構建所有底層數組。我應該注意到存在未知數量的嵌套數組,並且我不能簡單地轉換爲字符串並刪除空行,因爲我在非常大的索引上得到OutOfMemoryExceptions。

+0

你想要形成一個json字符串嗎? –

+0

你是什麼意思?我只需要一個包含所有具有非空值的索引的字符串。 – Cool12309

+1

數組是特定類型T的對象的固定大小集合。我無法看到數組如何包含類型T的對象以及'嵌套數組(大概是類型T)。請解釋。 –

回答

3

如果我假設DatabaseArray.GetValue()可以返回另一個DatabaseArray你可以創建一個遞歸方法是這樣的:

 private string GetArrayString(object dbArray) 
     { 
      if (dbArray == null) return null; 

      var arrayString = "{"; 
      var copiedarray = (DatabaseArray)dbArray; 
      for (var i = 0; i < copiedarray.Count; i++) 
      { 
       if (copiedarray.Contains(i)) 
       { 
        if (arrayString != "{") 
        { 
         arrayString = arrayString + ", "; 
        } 
        var value = copiedarray.GetValue(i); 
        arrayString = arrayString + i + ": " + (value is DatabaseArray ? this.GetArrayString(value) : value); 
       } 
      } 
      arrayString += "}"; 
      return arrayString; 
     } 

然後調用它像這樣:

DatabaseArray copiedarray = (DatabaseArray)result.GetValue(i); 
return GetArrayString(copiedarray); 

那應該輸出這個:

{3: {1: 2}, 4: 5} 
+1

美麗!最簡單的解決方案是最好的! – Cool12309

1

這就是我要做的,但我不完全確定是否理解數組的格式。此方法假定object []數組中的每個項都是一個字符串或另一個數組(然後由字符串或數組等組成)。

private static void ToFormattedString(this object[] array) 
    { 
     var res = array.Select((item, index) => 
          new { Index = index, Item = item is IEnumerable<object> 
              ? (item as object[]).ToFormattedString() 
              : item }) 
         .Where(i => i.Item != null); 

     return "{" + string.Join(", ", res.Select(r => r.Index.ToString() + ": " + r.Item.ToString())) + "}"; 
    } 

用法:

object[] array = //Get the array 

string arrayString = array.ToFormattedString(); 
1

聽起來像是遞歸工作!我不完全確定這是什麼用例,但是在一個非常基本的層面上,因爲你遞歸地寫出每個數組,所以你應該寫...好...遞歸方法。

public string GetArrayString() 
     { 
      var arrayValues = new object[]{ 
       1,2,3,new[]{4,5,6} 
      }; 

      return this.FormatArrayValues(arrayValues); 
     } 

     public string FormatArrayValues(IEnumerable<object> arrayValues) 
     { 
      String s = "{"; 

      arrayValues = arrayValues.Where(w=>w != null).ToArray(); 

      for(int j = 0; j < arrayValues.Count();j++){ 

       var currentValue = arrayValues.ElementAt(j); 

       if(currentValue is int[]) 
       { 
        var currentValueAsArrayOfObj = ((int[])currentValue).Cast<object>(); 
        currentValue = this.FormatArrayValues(currentValueAsArrayOfObj); 
       } 

       s += String.Format("{0}:{1}{2}",j, currentValue, j + 1 != arrayValues.Count() ? "," : null); 

      } 

      s += "}"; 

      return s; 
     } 

作爲一個側面說明,爲什麼你需要的條款if (copiedarray.Contains(j)){},如果你是通過遍歷數組......不應該總是包含「J」。

此外,'foreach'有時是一個更清晰的循環,您可以使用Linq的'ElementAt()'方法檢索索引。在這種情況下,for-loop可能更好,但我想我會提到它。

+0

我在arrayValues行發生錯誤:不能隱式地將類型'System.Collections.Generic.IEnumerable '轉換爲'string []'。存在明確的轉換(您是否缺少演員?)。此外,不,它不會,因爲值被放置在特定的索引(如在索引5可能有一個值,但指數2不會) – Cool12309

0

由於System.Array是特殊的,所以不能直接從它繼承:您的DatabaseArray必須是非數組的東西。因此,假設您的DatabaseArray是一些類似數組的對象,它實現了非泛型的System.Collections.IList(這是所有數組和類似對象都應該做的或者應該做的事情:D)...

您可以將嵌套數組看作樹的一種形式。

走這樣一棵樹是一個簡單的遞歸算法。以下應該是你的。您需要提供:

  • 您的樹的根節點(最初的IList)。
  • StringBuilder例如在其上構建出字符串
  • 的行爲 - 一個委託方法或閉合負責字符串化非空數據對象。這visitNode委託必須有簽名

    void visitNode(int i , object o , StringBuilder sb) ; 
    

這一切Action需要做的就是追加object的字符串表示形式及其int指數爲StringBuilder。最簡單的格式是簡單的東西如:

visitNode(int i , object o , StringBuilder sb) 
{ 
    sb.AppendFormat("{0} : {1}" , i , o) ; 
} 

一旦TreeWalk完成時,StringBuilder應該有格式化字符串。只需調用其ToString()方法和鮑勃的叔叔。

static void TreeWalk(IList list , StringBuilder buffer , Action<int,object,StringBuilder> visitNode , int? index) 
{ 
    // Enforce the contract's preconditions 
    if (list  == null) throw new ArgumentNullException("list"  ) ; 
    if (buffer == null) throw new ArgumentNullException("buffer" ) ; 
    if (visitNode == null) throw new ArgumentNullException("visitNode") ; 

    // write the lead-in curly brace, prefixed with the optional index 
    if (index.HasValue) 
    { 
    buffer.Append(index.Value).Append(" : ") ; 
    } 
    buffer.Append("{" ) ; 

    // visit each direct child 
    for (int i = 0 ; i < list.Count ; ++i) 
    { 
    // write the item separator 
    if (i > 0) 
    { 
     buffer.Append(" , ") ; 
    } 

    // get the current child 
    object child = list[i] ; 


    if (child == null) 
    { 
     // if the child is null, we skip it 
     continue ; 
    } 
    else if (child is IList) 
    { 
     // if the child is a [nested] IList, we recursively visit it 
     TreeWalk((IList)child , buffer , visitNode) ; 
    } 
    else 
    { 
     // if the child is anything else, it's data: just visit it 
     visitNode(i , child , buffer) ; 
    } 

    } 

    // write the lead-out curly brace 
    buffer.Append(" }") ; 

    return ; 
} 
+0

所有這些IList給我一個錯誤:使用泛型類型'系統.Collections.Generic.IList '需要1個類型參數。另外,這對我來說太過先進了,你將不得不貶低它。 – Cool12309

+0

那是因爲你需要引用'System.Collections'。 這不是一個通用的接口。這就像它變得簡單一樣。將遞歸轉換爲顯式使用堆棧是相當簡單的,但它並沒有讓它變得更簡單。 如果您不想處理'Action'委託'visitNode',只需將它從原型中刪除,並將調用'visitNode'的行替換爲'buffer.AppendFormat(「{0}:{1} 「,我,孩子);' –