【问题标题】:Array/List that can Grow in two directions?可以向两个方向增长的数组/列表?
【发布时间】:2021-10-23 17:54:40
【问题描述】:

好的,这是我的目标:

  • 一个数组,我可以在末尾扩展而不会弄乱索引
  • 即使我想添加一个新对象,在索引 3 处输入的对象也应保留在索引 3 处 在位置“-1”(-1 是初始开始位置之前的位置)
  • 数组中可能有空单元格,以后可以填充

到目前为止我的想法:

  • 使用带字符串的字典
    • 可能一直在字符串和数字之间解析效率低下
  • 使用偏移量,只是使阵列更大
    • 我认为这会导致创建很多听起来效率很低的数组
      • 也许一些更智能的算法可以增加数组大小(将其加倍/增加 25 而不是 1)
  • 使用两个数组,一个用于正值,一个用于负值
    • 在接近零位时似乎很难使用

我需要这个做什么:
我想制作一个游戏,玩家可以扩展基于 2D 网格的世界,并且新放置的瓷砖周围的瓷砖非常重要(dorfromantik 和 Islanders 之间的混合)

【问题讨论】:

  • “使用带字符串的目录” - 什么?你的意思是Dictionary
  • 拥有包含索引的类的属性。从 1,000,000 开始索引。以后/从不担心性能。
  • “可能一直在字符串和数字之间进行低效解析”是什么意思?
  • 使用List 并使用Add(item) 在末尾附加项目或使用Insert(0, item) 在开头预附加项目怎么样?
  • 嗨。对于这个任务,我认为你应该考虑链表或者双向链表。您可以追加、预先添加,而不必担心性能问题。 en.wikipedia.org/wiki/Doubly_linked_list

标签: c# arrays list unity3d


【解决方案1】:

这是一个使用字典的简单示例。希望能给大家一些思路

Dictionary<Vector2, object> map = new Dictionary<Vector2, object>();
int mapSize;

void Start()
{
    GenerateMap(8); // 8 = number of rows and columns

    UpdateTileValue(new Vector2(0, 0), "Here's my house"); //set the value of a specific tile

    ExpandMap(1); //add another layer to the map surface
}

private void GenerateMap(int size)
{
    mapSize = size;
    int lowerBound = Mathf.FloorToInt(mapSize / 2f);
    int upperBound = Mathf.CeilToInt(mapSize / 2f);

    for (int row = -lowerBound; row < upperBound; row++)
    {
        for (int column = -lowerBound; column < upperBound; column++)
        {
            Vector2 address = new Vector2(row, column);
            
            if (!map.ContainsKey(address))
                map.Add(address, null);
        }
    }
}

private void UpdateTileValue(Vector2 address, object value)
{
    if (map.ContainsKey(address))
        map[address] = value;
}

private void ExpandMap(int numLayers) => GenerateMap(mapSize + numLayers);

【讨论】:

  • 感谢一堆,我目前正在尝试仅使用带有偏移量的二维数组,但如果数学过于 Spagetti,我可能会回退到这个解决方案 ^^
【解决方案2】:

我没有对此进行全面测试,也没有实现所有方法,但这里有一种方法:

public class TwoEndedList<T> : IList<T>
{
    private List<T> _natural = new List<T>();
    private List<T> _negative = new List<T>();

    public T this[int index]
    {
        get => index < 0 ? _negative[-index - 1] : _natural[index];
        set
        {
            if (index < 0)
                _negative[-index - 1] = value;
            else
                _natural[index] = value;
        }
    }

    public int Count => _natural.Count + _negative.Count;

    public bool IsReadOnly => false;

    public void Add(T item)
    {
        _natural.Add(item);
    }

    public void AddLast(T item)
    {
        _natural.Add(item);
    }
    public void AddFirst(T item)
    {
        _negative.Add(item);
    }

    public void Clear()
    {
        _natural.Clear();
        _negative.Clear();
    }

    public bool Contains(T item) => _natural.Contains(item) || _negative.Contains(item);

    public void CopyTo(T[] array, int arrayIndex)
    {
        throw new NotImplementedException();
    }

    public IEnumerator<T> GetEnumerator()
    {
        for (var i = _negative.Count - 1; i >= 0; i--)
            yield return _negative[i];
        for (var i = 0; i < _natural.Count; i++)
            yield return _natural[i];
    }

    public int IndexOf(T item)
    {
        var index = _natural.IndexOf(item);
        if (index == -1)
        {
            index = -1 - _negative.IndexOf(item);
        }
        return index;
    }

    public void Insert(int index, T item)
    {
        throw new NotImplementedException();
    }

    public bool Remove(T item)
    {
        throw new NotImplementedException();
    }

    public void RemoveAt(int index)
    {
        throw new NotImplementedException();
    }

    IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}

现在你可以这样做了:

var tel = new TwoEndedList<int>();

tel.Add(4);
tel.Add(5);
tel.AddFirst(1);
tel.AddFirst(2);

foreach (var x in tel)
{
    Console.WriteLine(x);
}

Console.WriteLine(tel[-2]);
Console.WriteLine(tel[-1]);
Console.WriteLine(tel.IndexOf(2));

这给了我:

2
1
4
5
2
1
-2

【讨论】:

  • 是的,这与我使用的 atm 接近,即使您的实现看起来更干净
  • 我也在使用数组,因为对象之间可能存在“空白”
猜你喜欢
  • 2019-10-01
  • 2011-03-23
  • 1970-01-01
  • 2016-01-23
  • 2011-04-04
  • 2014-07-03
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
相关资源
最近更新 更多