从数组递归构建字符串

时间:2014-01-31 00:37:03

标签: c# arrays

我有一个数组,它将值放在特定的索引上,如下所示:

{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。

4 个答案:

答案 0 :(得分: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 :(得分: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();

答案 2 :(得分: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可能更好,但我想我会提到它。

答案 3 :(得分:0)

由于System.Array很特殊,因此无法直接从中继承:您的DatabaseArray必须是数组以外的其他内容。因此,假设您的DatabaseArray是一个类似于数组的对象,它实现了非泛型System.Collections.IList(所有数组和类似数组的对象都做......或者应该做的事情:D)。 ..

您可以将嵌套数组视为一种树形式。

走这样一棵树是一种简单的递归算法。以下应该是你。您需要提供:

  • 树的根节点(最初的IList)。
  • 构建字符串
  • StringBuilder实例
  • Action - 一个委托方法或闭包,负责对非空数据对象进行字符串化。此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()方法和bob的你的叔叔。

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 ;
}