2014-01-31 3 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). Пожалуйста, объясни. –

ответ

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 ' to 'string []'. Явное преобразование существует (вам не хватает роли?).Кроме того, нет, это не так, потому что значения размещаются по определенным индексам (например, индекс 5 может иметь значение, но индекс 2 не будет) – Cool12309

0

С System.Array является специальным, на него нельзя непосредственно унаследовать: ваш DatabaseArray должен быть чем-то иным, чем массив. Итак, предположим, что ваш DatabaseArray - это некоторый объект, похожий на массив, который реализует не общий код System.Collections.IList (что-то, что все массивы и объекты типа массива ... или должны делать: D) ...

Вы можете посмотрите на вложенные массивы как на форму дерева.

Прогулка по такому дереву является простым рекурсивным алгоритмом. Вы должны сделать следующее.Вам необходимо будет предоставить:

  • Корневой узел вашего дерева (начальный IList).
  • StringBuilder пример, в котором для построения строкового
  • действия, - метод делегата или закрывающей ответственности stringifying ненулевых данные объектов. Этот 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

Все эти ИЛИС дают мне сообщение об ошибке: Использование универсального типа «Система .Collections.Generic.IList 'требует 1 аргумент типа. Кроме того, для меня это слишком продвинуто, вам придется окутать его. – Cool12309

+0

Это потому, что вам нужно ссылаться на 'System.Collections'. Это не общий интерфейс. И это примерно так же просто, как и получается. Трудно конвертировать из рекурсии в явное использование стека, но на самом деле это не делает его проще. И если вы предпочитаете не иметь дело с делегатом 'Action'' visitNode', просто удалите его из прототипа и замените строку, которая вызывает 'visitNode', на' buffer.AppendFormat ("{0}: {1} «, i, child);' –

Смежные вопросы