{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2fca322f",
   "metadata": {},
   "source": [
    "```{index} list\n",
    "```\n",
    "\n",
    "(list)=\n",
    "\n",
    "# List\n",
    "\n",
    "Arrays are fine if you know ahead of time how long your sequence of items is.\n",
    "Then you create your array with that length, and you are all set.\n",
    "\n",
    "If you want a variable sized container, you are likely to want a `List`.\n",
    "List is a type of collection that is used when the number of elements is unknown.\n",
    "As with arrays, you might want a collection of any particular type.\n",
    "Unfortunately, you cannot use the simple notation of arrays to specify\n",
    "the type of element in a `List`. Array syntax is\n",
    "*built into* the language. Lists are handled in the *library* of types\n",
    "provided by C# from .NET.\n",
    ".. There are all sorts of situations where you might want\n",
    ".. a general idea to have a version for each of many kinds of objects.\n",
    "\n",
    "```{index} generics < > for generics\n",
    "```\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "28b9626d",
   "metadata": {},
   "source": "## Generics\n\nSince .NET 4.0, the one new form of syntax that can apply to all sorts of\nclasses, *generics* is introduced. There is a namespace for the generics\nfor collections, including List: `System.Collections.Generic`. You used to have\nto use the `using` directive to *import* the features offered by the class but\nC# now does it automatically. In general, the new generic syntax allows a type in angle\nbrackets after a class (e.g., List) name.\n\nThe type for a generic list collection is:\n\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5965e0b3",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "List<T>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66aa8585",
   "metadata": {},
   "source": [
    "\n",
    "To create a list, you specify a type parameter for the type of data\n",
    "the variable will store. For example, to create a list of string type:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19dd9d21",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "List<string> myNames = new List<string>();\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2dcb029",
   "metadata": {},
   "source": [
    "\n",
    "Examples of adding elements to a list:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b1fd0c6",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "myNames.Add(\"Alice\");\n",
    "myNames.Add(\"Bob\");\n",
    "myNames.Add(\"Charles\");\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7ea62a0",
   "metadata": {},
   "source": [
    "\n",
    "To loop through a list, you may use the foreach loop:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "451bbd4c",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "foreach (string name in myNames)\n",
    "{\n",
    "    Console.WriteLine(name);\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "444a9044",
   "metadata": {},
   "source": [
    "\n",
    "Similarly, to create a list of integer type:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d3e453ac",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "List<int> primeNumbers = new List<int>();\n",
    "primeNumbers.Add(2); // adding elements using add() method\n",
    "primeNumbers.Add(3);\n",
    "primeNumbers.Add(5);\n",
    "primeNumbers.Add(7);\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0767e143",
   "metadata": {},
   "source": [
    "\n",
    "```{index} List; Add, Remove, Contains\n",
    "```\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "549f4458",
   "metadata": {},
   "source": "## List Constructors and Methods\n\nWe can play with some `List` methods in csharprepl. Note that csharprepl\ninformally displays the values of a `List` with Name and Type in a table like:"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "10486890",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "words"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6fc44525",
   "metadata": {},
   "source": [
    "The blocks below are all from one csharprepl session, with our comments\n",
    "breaking up the sequence. With the no-parameter `constructor` (the parentheses at the\n",
    "end of the variable declaration), the `List` is empty to start:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11b28674",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "List<string> words = new List<string>();\n",
    "words;\n",
    "words.Count"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2be68f1f",
   "metadata": {},
   "source": [
    "You can add elements, and keep count with the `Count` property\n",
    "as the size changes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e9886c2d",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "words.Add(\"Apple\");\n",
    "words\n",
    "words.Add(\"Banana\");\n",
    "words\n",
    "words.Add(\"Cherry\");\n",
    "words\n",
    "words.Count;\n",
    "words.Count"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d091cbf",
   "metadata": {},
   "source": [
    "```{index} list; index\n",
    "```\n",
    "\n",
    "You can reference and change elements by index, like with `arrays`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a1464a80",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "words[0];\n",
    "words[2];\n",
    "words[2] = \"Coconut\";\n",
    "words;"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1edd3fa0",
   "metadata": {},
   "source": [
    "You can use `foreach` like with arrays or other sequences:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0fb9f718",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "foreach (string s in words)\n",
    "{\n",
    "Console.WriteLine(s.ToUpper());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3ddb1e2",
   "metadata": {},
   "source": [
    "```{index} List; Console.WriteLine useless\n",
    "```\n",
    "\n",
    "Note: Unfortunately C# is not user-friendly if\n",
    "you try to use `Console.WriteLine` to print a `List` *object*:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64c07bf6",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "Console.WriteLine(words)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "835a8fa7",
   "metadata": {},
   "source": [
    "Next, compare `Remove`, which finds the first matching element and removes it,\n",
    "and `RemoveAt`, which removes the element at a specified index.\n",
    "`Remove` returns whether the List has been changed:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f56a7a3",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "words.Remove(\"Apple\");\n",
    "words\n",
    "words.Add(\"Avocado\");\n",
    "words.Add(\"Durian\");\n",
    "words\n",
    "words.RemoveAt(3)\n",
    "words"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "525e6c78",
   "metadata": {},
   "source": [
    "Removing does not leave a \"hole\" in the `List`: The list closes up,\n",
    "so the index decreases for the elements after the removed one:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0acdea07",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "words.Count;"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd346df0",
   "metadata": {},
   "source": [
    "You can check for membership in a `List` with `Contains`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11602105",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "words.Contains(\"Apple\")\n",
    "words.Contains(\"Banana\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fac41358",
   "metadata": {},
   "source": [
    "You can also remove all elements at once:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1802b84",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "words.Clear()\n",
    "words"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb657d05",
   "metadata": {},
   "source": [
    "```{index} List; constructor with sequence\n",
    "```\n",
    "\n",
    "Here is a List containing `int` elements.\n",
    "Though more verbose than for an array, you can initialize a `List`\n",
    "with another collection, including an `anonymous array`,\n",
    "specified with an explicit sequence in curly braces:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e63082d5",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "List<int> nums = new List<int>(new[] { 1, 2, 3, 4, 5 });\n",
    "nums"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8075985",
   "metadata": {},
   "source": [
    "We have been using the explicit declaration syntax, but generic types tend to get long,\n",
    "so the keyword `var` for implicitly-typed variable creation is handy with them:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "95ea244a",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "var stuff = new List<string>();\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45ff4851",
   "metadata": {},
   "source": [
    "\n",
    "When initializing a generic object, you still need to remember both the angle braces\n",
    "around the type *and* the parentheses for the parameter list after that. Or, you can\n",
    "try initializing a collection object with *collection initialization*:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "071bf7bd",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };\n",
    "List<int> digits2 = new List<int> { 0 + 1, 12 % 3, MakeInt() };\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "862d369e",
   "metadata": {},
   "source": [
    "\n",
    "% .. index:: side effect\n",
    "\n",
    "% An aside on the ``Remove`` method: It both causes a side effect,\n",
    "\n",
    "% changing the list, *and* it returns a value. If a function returns a value,\n",
    "\n",
    "% we typically use the method call as an expression in a larger statement. The\n",
    "\n",
    "% ``Remove`` method illustrates that this is\n",
    "\n",
    "% not always a mistake: If you just want the side effect, trying to remove an element,\n",
    "\n",
    "% whether or not it is in the list, then there is no need to check for the return value.\n",
    "\n",
    "% This complete C# statement is fine::\n",
    "\n",
    "% someList.Remove(element);\n",
    "\n",
    "% You should generally think carefully before *defining* a method\n",
    "\n",
    "% that both has a side effect and a return value. Most methods that return a value\n",
    "\n",
    "% do not have a side effect. If you see a function used in the normal way as an\n",
    "\n",
    "% expression, it is easy to forget that it was *also* producing some side effect.\n",
    "\n",
    "```{index} List; ReadLines\n",
    "```\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eef202b0",
   "metadata": {},
   "source": "## Interactive List Example\n\nAs in contrast to `array`, `lists` are handy when you do not know how much\ndata there will be. A simple example would be reading in lines from the user\ninteractively:\n\n"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "841e5ee6",
   "metadata": {
    "language_info": {
     "name": "polyglot-notebook"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "/// Return a List of lines entered by the user in response\n",
    "/// to the prompt.  Lines in the List will be nonempty, since an\n",
    "/// empty line terminates the input.\n",
    "List<string> ReadLines(string prompt)\n",
    "{\n",
    "   List<string> lines = new List<string>();\n",
    "   Console.WriteLine(prompt);\n",
    "   Console.WriteLine(\"An empty line terminates input.\");\n",
    "   string line = Console.ReadLine();\n",
    "   while (line.Length > 0) {\n",
    "      lines.Add(line);\n",
    "      line = Console.ReadLine();\n",
    "   }\n",
    "   return lines;\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "footnotes",
   "metadata": {},
   "source": "```{rubric} Footnotes\n```\n"
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  },
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "csharp"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}