C# 如何在Unity中筛选/搜索列表

C# 如何在Unity中筛选/搜索列表,c#,unity3d,filtering,C#,Unity3d,Filtering,我正试图想出一种方法来过滤我动态创建的按钮列表,该列表基于SQlite DB中循环的值。每个按钮都标有学生姓名,可能有大量按钮,因此需要过滤按钮 我创建的按钮如下所示: public RectTransform GridWithNameElements; public GameObject StudentNamePrefabButton; while (reader.Read()) { //create a new button obje

我正试图想出一种方法来过滤我动态创建的按钮列表,该列表基于SQlite DB中循环的值。每个按钮都标有学生姓名,可能有大量按钮,因此需要过滤按钮

我创建的按钮如下所示:

public RectTransform GridWithNameElements;
public GameObject StudentNamePrefabButton;

while (reader.Read())
            {
                //create a new button object and use the prefab button to make sure spacing etc is correct
                goButton = (GameObject)Instantiate(StudentNamePrefabButton);
                //set the parent of the button
                goButton.transform.SetParent(GridWithNameElements, false);
                goButton.transform.localScale = new Vector3(1, 1, 1);
                //set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
                goButton.GetComponentsInChildren<Text>()[0].text = reader["fullName"].ToString()+" | "+ reader["studentNumber"].ToString();
                goButton.name = reader["studentID"].ToString();

                Button tempButton = goButton.GetComponent<Button>();
                int tempInt = i;

                tempButton.onClick.AddListener(() => ButtonClicked(tempInt));

                i++;

                Debug.Log(goButton.name);
            }
我希望简单地遍历所有列表项,并隐藏那些与搜索查询不匹配的项。然而,目前,我的循环是错误的,因为我得到了一个越界异常(我认为这与在进行搜索时动态添加一个新的子元素有关)。我在控制台日志中看到了这一点,但是,程序按预期执行(因此这是一个问题,但目前不是最大的问题)

我隐藏原始列表,并根据匹配条件显示新列表

然而,我只返回一个可能的名字,而不是一堆可能的选择。例如,根据我目前的代码,如果我有本·琼斯和鲍勃·迪伦的名字,我只能返回本·琼斯,而不能返回鲍勃·迪伦

我觉得我在做这件事时走错了方向,因为我想要类似的东西,但无法重现。然而,我正试图弄清楚我是否朝着正确的方向前进

更新

我想我已经找到了
索引自动失效异常的原因:数组索引超出范围。
这是因为每当我键入字母时,它都在调用
SearchExistingStudentName()
方法。这意味着,只要在其中一个名称中找到键入的字母,它就会被添加到列表中—仅添加字母。这就是为什么我只能返回一个名字,而不是可能的名字列表。因此,我认为国际单项体育联合会的声明需要修改,我现在正在努力研究这一点

我已设法将代码中的数组异常缩小到本节:

//Loop through and hide all children and hide them
if (count == 0)
{
foreach (Transform child in GridWithNameElements)
  {
child.gameObject.SetActive(false);
  }
}

count++;

//Then create a button that represents a name added to the names List
newButton = (GameObject)Instantiate(StudentNamePrefabButton);
//set the parent of the button
newButton.transform.SetParent(GridWithNameElements, false);
newButton.transform.localScale = new Vector3(1, 1, 1);
//set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
newButton.GetComponentsInChildren<Text>()[filteredNameCount].text = names[filteredNameCount].ToString();
newButton.name = names[filteredIDCount].ToString().Trim();
                    newButton.tag = "filterButton";

filteredNameCount++;
filteredIDCount++;
//循环并隐藏所有子项并隐藏它们
如果(计数=0)
{
foreach(在GridWithNameElements中转换子级)
{
child.gameObject.SetActive(false);
}
}
计数++;
//然后创建一个按钮,该按钮表示添加到名称列表中的名称
newButton=(游戏对象)实例化(StudentNameButton);
//设置按钮的父级
SetParent(GridWithNameElements,false);
newButton.transform.localScale=新向量3(1,1,1);
//设置按钮的文本。数组值为0,因为学生名称在每次迭代中始终位于位置0
newButton.GetComponentsInChildren()[filteredNameCount].text=名称[filteredNameCount].ToString();
newButton.name=名称[FilterEdicount].ToString().Trim();
newButton.tag=“filterButton”;
filteredNameCount++;
filterediccount++;

既然您已经用Unity3D标记了此代码,我假设您希望在游戏中使用此代码。如果是这种情况,我不建议使用LINQ,如果可以用更传统的方式轻松获得相同的结果。话虽如此,我将展示这两种方法

List<string> names = GridWithNameElements.Where(nameInList => nameInList.Contains(input))

我对变量的类型不完全有信心,但我认为结构应该足够清晰。如果不是的话,请随意询问更多问题。

最终我自己设法解决了这个问题,尽管这远不是一个优雅的解决方案,但它还是有效的。我现在将致力于改进代码本身,但对于那些可能需要一个起点的人,我想我会分享我所做的

正如在我的问题中提到的,我在我的主、未过滤的可滚动列表上循环了一系列按钮

while (reader.Read())
            {
                //create a new button object and use the prefab button to make sure spacing etc is correct
                GameObject goButton = (GameObject)Instantiate(StudentNamePrefabButton);
                //set the parent of the button
                goButton.transform.SetParent(GridWithNameElements, false);
                goButton.transform.localScale = new Vector3(1, 1, 1);
                //set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
                goButton.GetComponentsInChildren<Text>()[0].text = reader["fullName"].ToString() + " | " + reader["studentNumber"].ToString();
                goButton.name = reader["studentID"].ToString();

                Button tempButton = goButton.GetComponent<Button>();
                int tempInt = i;

                tempButton.onClick.AddListener(() => ButtonClicked(tempInt));

                i++;

                Debug.Log(goButton.name);
            }

为什么不在循环中使用
nameInList
变量?关于使用切换呢?也许会让你的生活更轻松!谢谢你的回答。自从你发布这篇文章以来,我已经为我的问题添加了更多的细节,因为我觉得解决方案比最初解释的要复杂一些。我无法使用您的
字符串名称列表的语法
,因为我遇到了一个
错误,即无法从源类型转换为目标类型
。我现在使用的是一个简单的for循环,如更新中所示。我比以前更进一步了,但正如更新的问题所表明的,仍然存在一些bug。
List<string> names = new List<string>();
foreach (string nameInList in GridWithNameElements)
{
    if (nameInList.Contains(input)
    {
        names.Add(nameInList)
    }
}
while (reader.Read())
            {
                //create a new button object and use the prefab button to make sure spacing etc is correct
                GameObject goButton = (GameObject)Instantiate(StudentNamePrefabButton);
                //set the parent of the button
                goButton.transform.SetParent(GridWithNameElements, false);
                goButton.transform.localScale = new Vector3(1, 1, 1);
                //set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
                goButton.GetComponentsInChildren<Text>()[0].text = reader["fullName"].ToString() + " | " + reader["studentNumber"].ToString();
                goButton.name = reader["studentID"].ToString();

                Button tempButton = goButton.GetComponent<Button>();
                int tempInt = i;

                tempButton.onClick.AddListener(() => ButtonClicked(tempInt));

                i++;

                Debug.Log(goButton.name);
            }
//This method is called when the student attempts to search for their own name when taking the individual quiz
public void SearchExistingStudentName()
{

    //Get the name entered from the text field
    string student_name = searchExistingStudentNameInput.text;

    //Create a list to store all the user names
    List<string> filteredNamesList = new List<string>();
    //Add another list to store the user unique ids
    List<string> filteredNameIDList = new List<string>();

    //Clear both lists before using them
    filteredNamesList.Clear();
    filteredNameIDList.Clear();
    //sets an id to the onclick listener of newly created buttons
    int x = 0;

    //if a new button object exists and the name was entered and then removed, clear it from the list and remove the created button
    if (student_name == "")
    {
        //Clear the filtered filteredNamesList List
        filteredNamesList.Clear();
        filteredNameIDList.Clear();
        x = 0;
        //Destroy the create filter buttons if the user clears the text area
        GameObject[] objects = GameObject.FindGameObjectsWithTag("filterButton");
        //loop through the buttons that share the tag "filterButton"
        for (int count = 0; count < objects.Length; count++)
        {
            Destroy(objects[count]);

            Debug.Log("Number of objects to be deleted " + objects.Length);
        }

        //Loop through and show all children 
        foreach (Transform child in GridWithNameElements)
        {
            child.gameObject.SetActive(true);
        }

        GridWithNameElements.gameObject.SetActive(true);
        GridWithNameElements2.gameObject.SetActive(false);
    }
    else if (student_name != "")
    {

        //loop through the list of buttons in the main/unfiltered list with student filteredNamesList
        for (int i = 0; i < GridWithNameElements.childCount; i++)
        {
            //Check if the user has typed their name with capitals or lowercase etc, and check the inputted value against filteredNamesList already in the list
            //If true, proceed 

            //Get the name value that contains entered character
            if (GridWithNameElements
               .GetComponentsInChildren<Text>()[i].text.Contains(student_name) || GridWithNameElements
               .GetComponentsInChildren<Text>()[i].text.ToLower().Contains(student_name) || GridWithNameElements
               .GetComponentsInChildren<Text>()[i].text.ToUpper().Contains(student_name))
            {

                //Do not allow duplicates to the list
                if (filteredNamesList.Distinct().Count() == filteredNamesList.Count())
                {
                    //If the name entered contains letters found in the parent GridWithNameElements, then add them to the list array and their name value (unique id)
                    filteredNamesList.Add(GridWithNameElements.GetComponentsInChildren<Text>()[i].text.Replace(@"[", string.Empty).Replace(@"]", string.Empty));
                    filteredNameIDList.Add(GridWithNameElements.GetChild(i).name); //this is the unique id of the student
                }

                //end of if statement   
            }
            //end of main loop
        }
        //hide original list
        GridWithNameElements.gameObject.SetActive(false);
        //show filtered list
        GridWithNameElements2.gameObject.SetActive(true);

        //Destroy the created filter buttons if the user presses another button, as previously 
        //added filteredNamesList might need to be ruled out. 
        GameObject[] objects = GameObject.FindGameObjectsWithTag("filterButton");
        //loop through the buttons that share the tag "filterButton"
        for (int count = 0; count < objects.Length; count++)
        {
            Destroy(objects[count]);

            Debug.Log("Number of objects to be deleted " + objects.Length);
        }

        int filteredNameIDCount = 0;

        foreach (string nameInList in filteredNamesList)
        {


            //Then create a button that represents a name added to the filteredNamesList List
            newButton = Instantiate(StudentNamePrefabButton);
            //set the parent of the button
            newButton.transform.SetParent(GridWithNameElements2, false);
            newButton.transform.localScale = new Vector3(1, 1, 1);
            //set the text of the button. Array value is 0 as the student name is always at position 0 on each iteration
            newButton.GetComponentsInChildren<Text>()[0].text = nameInList.ToString();
            newButton.name = filteredNameIDList[filteredNameIDCount].ToString().Trim();
            newButton.tag = "filterButton";

            Debug.Log("Filtered Name " + nameInList.ToString() + " Their ID " + filteredNameIDList[filteredNameIDCount].ToString().Trim());

            filteredNameIDCount++;

        }
        //end of loop


        //Then add a click listener to the button
        Button tempButton = newButton.GetComponent<Button>();
        int tempInt = x;

        tempButton.onClick.AddListener(() => ButtonClicked(tempInt));

        x++;

        // Debug.Log("Student Unique ID " + newButton.name);

    }

}