按名称访问唯一数组

Posted

技术标签:

【中文标题】按名称访问唯一数组【英文标题】:Accessing unique array by name 【发布时间】:2017-10-09 22:02:02 【问题描述】:

我有一组像这样的整数数组-

public int[] box1 = 1, 0, 2;
public int[] box2 = 3, 1, 0;
public int[] box3 = 2, 3, 1;

我需要做的是通过唯一的数组名称动态访问它们,并从中返回一个随机元素,使用类似这样的东西-

foo="box"+2[random int];

其中 foo 是我的临时字符串,包括“box”前缀,将我想要的数字添加到“box”,并从“box2”中获取一个随机元素。 (例如:foo=3)

如果我通过字符串方法执行此操作,它会创建正确的命名法,但它只是一个字符串,我不能使用它在脚本中实际访问这些作为实际的类/数组元素并将它们传递给其他东西。

我该怎么做呢?阅读手册几个小时,尝试了列表,但我认为我做的不对。谢谢!

【问题讨论】:

您正在寻找Dictionary 不是Dictionary,而是Lookup 不是DictionaryLookup,而是带有indexer 的自定义类 或数组数组:box[2][random int]; 我决定用Dictionary 留下答案,因为没有人留下满足您问题语法的答案。希望能解决问题。 【参考方案1】:

只需分解您真正想做的事情,您就会发现它是多么容易。就像我在评论部分提到的Dictionary 一样,您仍然需要另外两个 C# 功能来完成确切的语法。

你希望能够做到这一点:

foo="box"+2[random int];

与此相同:

int valueFromArray  = arrayVariableName [index];

在下面的示例中,我们可以假设 MyScript 是我们脚本的名称。

1。你需要一个可以保存名字和int数组的字典。

Dictionary<string, int[]> boxes

2。您需要一种将 "box"+2arrayVariableName 转换为当前脚本实例的方法。这可以通过 C# 中的隐式转换运算符功能来完成。您可以将 "box"+2arrayVariableName 传递到这个隐式 MyScript 中,然后将其存储到全局变量中以供下一步使用。

//The global variable that holds the arrayVariableName to access
static string targetBox = null;

//Implicit conversion operators (box array name to this script(MyScript) instance)
public static implicit operator MyScript(string box)

    return setTargetAndGetInstance(box);


public static MyScript setTargetAndGetInstance(string box)

    if (instance.boxes.ContainsKey(box))
    
        //Set the box requested. This will be needed in the Indexer overloading above
        targetBox = box;
        return instance;
    
    else
        return null;

3。现在,您可以实现 [index] 语法。这可以通过索引器重载功能来实现。

//Indexer overloading (index to int (value in array))
public int this[int index]

    get
    
        //Get value based on value set in the implicit operators
        return accessBox(targetBox, index);
    

现在,当你这样做时,"box"+2,它将在 implicit 转换运算符的帮助下返回 this(MyScript) 的实例。然后它将允许您使用索引器重载功能执行 [random int]


下面的代码是您问题中的语法示例以及执行此操作的其他类似方法。 包括类似的,因为它们看起来比您要求的更好

用一个简单的功能:

int test1 = accessBox("box" + 2, UnityEngine.Random.Range(0, 3));
Debug.Log(test1);

使用arrayVariableName [index] 语法:

你正在寻找这个,但 MyScript 的转换看起来很糟糕

int test2 = ((MyScript)("box" + 2))[UnityEngine.Random.Range(0, 3)];
Debug.Log(test2);

使用[arrayVariableName][index] 语法:

int test3 = this["box" + 2][UnityEngine.Random.Range(0, 3)];
Debug.Log(test3);

使用[arrayVariableName, index] 语法

int test4 = this["box" + 2, UnityEngine.Random.Range(0, 3)];
Debug.Log(test4);

完整的功能示例:

using System.Collections.Generic;
using UnityEngine;

public class MyScript : MonoBehaviour


    public int[] box1 =  1, 0, 2 ;
    public int[] box2 =  3, 1, 0 ;
    public int[] box3 =  2, 3, 1 ;


    public Dictionary<string, int[]> boxes = new Dictionary<string, int[]>();
    private static MyScript instance;

    void Awake()
    
        instance = this;

        //Add to Dictionary
        addBox();

        int test1 = accessBox("box" + 2, UnityEngine.Random.Range(0, 3));
        Debug.Log(test1);

        int test2 = ((MyScript)("box" + 2))[UnityEngine.Random.Range(0, 3)];
        Debug.Log(test2);

        int test3 = this["box" + 2][UnityEngine.Random.Range(0, 3)];
        Debug.Log(test3);

        int test4 = this["box" + 2, UnityEngine.Random.Range(0, 3)];
        Debug.Log(test4);
    

    void addBox()
    
        boxes.Add("box1", box1);
        boxes.Add("box2", box2);
        boxes.Add("box3", box3);
    

    public int accessBox(string box, int index)
    
        //Return the array from the Dictionary
        int[] tempVar;
        if (boxes.TryGetValue(box, out tempVar))
        
            //Return the spicified index
            return tempVar[index];
        
        else
        
            //ERROR - return -1
            return -1;
        
    


    //Indexer overloading (index to int (value in array))
    public int this[int index]
    
        get
        
            //Get value based on value set in the implicit operators
            return accessBox(targetBox, index);
        
    

    static string targetBox = null;

    //Implicit conversion operators (box array name to this script(MyScript) instance)
    public static implicit operator MyScript(string box)
    
        return setTargetAndGetInstance(box);
    

    public static MyScript setTargetAndGetInstance(string box)
    
        if (instance.boxes.ContainsKey(box))
        
            //Set the box requested. This will be needed in the Indexer overloading above
            targetBox = box;
            return instance;
        
        else
            return null;
    

    //Indexer overloading (box array name to this script(MyScript) instance)
    public MyScript this[string box]
    
        get
        
            return setTargetAndGetInstance(box);
        
    

    //Indexer overloading (box array name to int)
    public int this[string box, int index]
    
        get
        
            setTargetAndGetInstance(box);
            return accessBox(box, index);
        
    

【讨论】:

【参考方案2】:

这是您的问题的通用解决方案,使用 Dictionary&lt;TKey,TValue&gt;

主要代码:

using System;
using System.Collections.Generic;

public class Class1

    public void Example()
    
        // a dictionary with string keys

        var string1 = "abcd";
        var string2 = "efgh";

        var dictionary1 = new Dictionary<string, int[]>
        
            string1, new[] 0, 1, 2,
            string2, new[] 3, 4, 5
        ;


        // a dictionary with custom type

        var box1 = new Box(10, 10);
        var box2 = new Box(20, 20);

        var dictionary2 = new Dictionary<Box, int[]>
        
            box1, new[] 0, 1, 2,
            box2, new[] 3, 4, 5
        ;

        // get random value from both dictionnaries

        var i1 = GetRandomInteger(dictionary1, string1);
        var i2 = GetRandomInteger(dictionary2, box1);
    

    private int GetRandomInteger<TKey>(IDictionary<TKey, int[]> dictionary, TKey key)
    
        if (!dictionary.ContainsKey(key))
            throw new KeyNotFoundException();

        var array = dictionary[key];

        // prefer UnityEngine.Random here since it's static 
        var index = new Random().Next(array.Length);

        var value = array[index];

        return value;
    

额外代码:

public struct Box

    // a dictionary key should be immutable, therefore I use a struct
    // implement equality members so that when querying the dictionary,
    // it will find the value associated to the key
    // see https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type

    public int Width  get; 
    public int Height  get; 

    public Box(int width, int height)
    
        Width = width;
        Height = height;
    

    public bool Equals(Box other)
    
        return Width == other.Width && Height == other.Height;
    

    public override bool Equals(object obj)
    
        if (ReferenceEquals(null, obj))
            return false;
        return obj is Box && Equals((Box) obj);
    

    public override int GetHashCode()
    
        unchecked
        
            return (Width * 397) ^ Height;
        
    

    public static bool operator ==(Box left, Box right)
    
        return left.Equals(right);
    

    public static bool operator !=(Box left, Box right)
    
        return !left.Equals(right);
    

【讨论】:

以上是关于按名称访问唯一数组的主要内容,如果未能解决你的问题,请参考以下文章

按名称访问 XML DOM 子节点

访问 SQL Randomizer 未按预期工作

SQL JSON PATH 如何在从较大的 json 集中提取后按索引访问 json 数组

访问从 Reactjs 中的状态创建的数组的数据时出现问题

如何使用验证“唯一”访问 Laravel 中的自定义文本框名称?

当从扩展符号访问对象时如何访问 Javascript 对象的嵌套按名称属性...?