how to find number of array list same as contains string, i want make contains string "guess1" get "answer1" and "guess2" get "answer2". how to find n number of array same as contains string?
public class FindContainsText : MonoBehaviour
{
public Text text;
public InputField intext;
List<string> guess = new List<string>();
List<string> answer = new List<string>();
private int n;
void Start()
{
guess.Add("test1");
guess.Add("test2");
answer.Add("answer1");
answer.Add("answer2");
}
// Update is called once per frame
void Update()
{
foreach (string x in guess)
{
if (intext.text.ToLower().Contains(x.ToLower()))
{
text.text = answer[n];
return;
}
}
text.text = "not found";
}
}
Then you should use Dictionary type.
private Dictionary<string, string> guessAnswerDict = new Dictionary<string, string>();
private void Start()
{
guessAnswerDict["test1"] = "answer1";
guessAnswerDict["test2"] = "answer2";
}
You can check whether the test exists in Dictionary with
guessAnswerDict.Contains("test1");
And get the answer value with
var answer = guessAnswerDict["test1"];
It will throw an exception when there are no key in dictionary, so you have to check it with Contains.
Of course you can merge these two with TryGetValue, like
string answer;
guessAnswerDict.TryGetValue("test1", out answer);
// Totally identical!!
guessAnswerDict.TryGetValue("test1", out var answer);
TryGetValue will return false if there are no key in the dictionary.
BTW, although C#'s default access modifier is private, it's always good to explicitly write it's private, which will increase the readability of your code :)
Related
I am trying to create a dictionary wherein a randomized key is generated, and when I click on a button, this randomized key is subsequently removed from the dictionary and stored in a separate list, so that when there are no longer any keys in the dictionary, as the process has been done X number of times, the dictionary is refreshed.
I'm planning on using this dictionary to further my understanding of using random numbers in unity, practicing it through making a 'simple' quiz dictionary. I have tried creating a separate list and refreshing it (which presumably did not work because I did the code wrong I guess...) and experimenting with creating more variables to control it, which also did not work.
public class textScript : MonoBehaviour
{
public static Dictionary<int, string> questionDict = new Dictionary<int, string>();
public static Dictionary<int, string> answerDict = new Dictionary<int, string>();
public static int randomkey;
public static int removekey;
// You also need to obtain the WRONG values, so you need 'dummy' randomised values
public static int wrongkey;
public static int wrongkey1;
public static int wrongkey2;
public static int wrongkey3;
// You also need to determine the right button
public static int correctbutton;
// In order to obtain question
public static bool nextQuestion;
public void Awake()
{
// Obtains the right dictionaries
questionDict = ES2.LoadDictionary<int, string>(control.question.ToString());
answerDict = ES2.LoadDictionary<int, string>(control.answer.ToString());
}
void Start()
{
nextQuestion = true;
}
void Update()
{
noRepeatAnswers();
randomiseKeys();
GetComponent<TextMeshProUGUI>().text = questionDict[randomkey];
}
void randomiseKeys()
{
if (nextQuestion == true)
{
Random rand = new Random();
for (int i = 0; i < questionDict.Count; i++)
{
randomkey = Random.Range(1, questionDict.Count);
wrongkey = Random.Range(1, questionDict.Count);
wrongkey1 = Random.Range(1, questionDict.Count);
wrongkey2 = Random.Range(1, questionDict.Count);
wrongkey3 = Random.Range(1, questionDict.Count);
}
// Store the above value in a float array
correctbutton = Random.Range(1, 4);
}
followingQuestion();
}
void followingQuestion()
{
nextQuestion = false;
}
The idea is that when you press the 4 buttons ( which use the other integers wrongkey etc.), they will remove this random value (randomkey) from the dictionary before a new question rolls out (through the Boolean), limiting the number of questions until it refreshes, when the value of the keys = null. When I created another list and removed key, the program just went into spasm and crashed.
The purpose of a Dictionary is to store "Keyed" values, literally as KeyValuePair<,>.
From your comments, what you're asking for is a way to group Q&A pairs into categories, then remove those categories. A Dictionary can be useful in that you can name the category, and retrieve a list of Q&A pairs using that name.
public class QandA {
public string Question;
public string Answer;
}
Dictionary<string, List<QandA> > Trivia;
public InitTrivia() {
Trivia = new Dictionary<string, List<QandA>>();
Trivia.Add( "Algebra", new List<QandA> {
new QandA { Question = "What is 2 + 2?", Answer = "Four" },
new QandA { Question = "What is 6 x 3?", Answer = "Eighteen" },
});
}
If you want to randomly select a topic (a random element between zero-inclusive and element count-exclusive):
using System.Linq;
var category = Trivia.Keys.ElementAt(Random.Range(0, Trivia.Keys.Count));
From that topic, randomly select a QandA pair (a random element between zero-inclusive and element count-exclusive):
var qaList = Trivia[category];
var qaInstance = qaList[Random.Range(0, qaList.Count)];
From there you probably want to remove the QandA from the list so it doesn't get re-asked, and remove any empty lists from the dictionary.
When you want to reset, it's probably easiest to just to re-run your original init() code (which will presumably load all the QandA from a save file/serialised source)
I managed to create an input field that is able to be checked and verified upon a question via creating another text field and linking that to said question, so for example if the value of the question was '1', the answer would be '1'. Then I made a text comparison, so that if what the user wrote = that text field the answer would be correct.
However, I realise that sometimes someone can write something else. For example in the question ' What do you think about tigers', there isn't just one possible answer. And therefore, the way I did that for the input field does not exactly work (does it?).
I did quite a lot of research and found out about dictionaries, but since they only have one key value that wouldn't help, and then I found out about lists, which might?
So my question is whether it is possible, and how, to create a list that's integer values is somehow linked to the values of the overarching question, so that if the random value is 1, the list value is 1 as well, and then check if what is written matches any of the answers with that random value.
If what I just said didn't make sense, here's an example:
Current behavior:
SURVEY: Do you like cats?
INPUT FIELD: Yes I do
HIDDEN TEXT FIELD : Yes I do
input field = hidden text field and therefore correct
Ideal behavior:
SURVEY: Do you like cats?
INPUT FIELD: I do like cats
POSSIBLE ANSWERS: I do like cats, Yes I do etc.
INPUT FIELD contains an answer in the list which matches the question and therefore correct.
I thought you could use the .Contains function, but I didn't know how to link it all together.
EDIT:
I tried to solve this problem via the creation of a dictionary and searching for a key (which I believe was the right way to do this), but for some reason this code doesn't even work when checking it? (it's like the .containsKey function doesn't work?)
public string questions = "hi;weird;by";
Dictionary<int, string> tester = new Dictionary<int, string>();
// Use this for initialization
void Start ()
{
tester.Add(1, questions);
tester.Add(2, "hello");
tester.Add(3, "by");
tester.Add(4, "hi");
tester.Add(5, "bye");
}
// Update is called once per frame
void Update ()
{
}
public void hello ()
{
if(tester.ContainsKey(2))
{
string value = tester[2];
Debug.Log("Correct");
}
}
EDIT 1:
Following what trashr0X said I tried doing it by having a dictionary script in the main camera and a script in the inputfield, but for some reason when I load it nothing works on the console:
LIST
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
public class Listpractice : MonoBehaviour
{
Dictionary<int, List<string>> tester = new Dictionary<int, List<string>>();
List<string> possibleAnswersToQuestionZero = new List<string>();
// Use this for initialization
void Start () {
possibleAnswersToQuestionZero.Add("Hello");
possibleAnswersToQuestionZero.Add("By");
tester.Add(0, possibleAnswersToQuestionZero);
}
// Update is called once per frame
void Update ()
{
}
public void hello ()
{
var toCheck = tester[0].FirstOrDefault(x => x == GameController.hello);
if (toCheck != null)
{
Debug.Log("Hi!");
}
}
}
INPUT FIELD
public class QAClass07
{
public string Answer = "";
public string Question = "";
QAClass07 result = new QAClass07();
}
public static string hello;
void Start()
{
GameObject a = gameObject;
hello = a.transform.Find("Text").GetComponent<Text>().text;
}
// registers what the user writes
public void getInput(string guess)
{
// Does something assuming someone enters something
if (GetComponent<InputField>() != null)
{
hello = GetComponentInChildren<Text>().text;
}
}
Simply use Dictionary<int, List<string>> and then add all the answers to the corresponding question id.
var questions = new List<string> { "hi", "weird", "by" };
var tester = new Dictionary<int, List<string>>();
// Use this for initialization
void Start ()
{
tester.Add(1, questions);
tester.Add(2, new List<string> { "hello" });
tester.Add(3, new List<string> { "by" });
tester.Add(4, new List<string> { "hi" });
tester.Add(5, new List<string> { "bye" });
}
public void hello ()
{
if(tester.ContainsKey(2))
{
var answers = tester[2] ?? new List<string>();
// now you have all answers linked to question with id 2 in answers variable
}
}
"I did quite a lot of research and found out about dictionaries, but since they only have one key value that wouldn't help, and then I found out about lists, which might?"
Yes, a Dictionary<TKey, TValue> does comprise of key-value pairs of a particular type each; you can declare the type of it's key to be int (corresponding to the index of the question currently asked), and declare the type of it's value to be List<string>, to hold possible answers for that question.
// key is question index, value is a list of possible answers for that question
var dictionary = new Dictionary<int, List<string>>();
// list of possible answers for question 0 (random question number chosen for the example)
var possibleAnswersToQuestionZero = new List<string>();
possibleAnswersToQuestionZero.Add("Possible Answer to question 0");
possibleAnswersToQuestionZero.Add("Another possible answer to question 0");
// add that list to the dictionary at key 0.
// you should be also checking if the key exists before trying to access it's value,
// and what happens if the list returned for that key is null or empty.
dictionary.Add(0, possibleAnswersToQuestionZero);
To check if the answer submitted by the user (let's assume it is saved in a variable named userInput) for question 0 is in the list of possible answers for that key, we would do:
// check if the list at dictionary[0] has at least one instance of userInput,
// otherwise return null
var toCheck = dictionary[0].FirstOrDefault(x => x == userInput);
// if the result is not null, the answer was found
if (toCheck != null)
{
// answer found
}
I am trying to add values to a dictionary as they get determined based on certain conditions. The app has to loop through each line and once a certain condition has been met then a value must be added to the dictionary. Here is the code that is task with looping through the lines and determine values to be added.
foreach (var line in this.FileLines)
{
count++;
string[] bits = line.Split(',');
fineNumber = bits[0].Trim();
int length = bits.Length;
if (length == 9)
{
//other processing gets done here, code not included as its of no interest for this question
}
else
{
//AddErrorFinesToFile(line, fineNumber);
AddFinesToDictonary(fineNumber, line);
continue;
}
}
Then below is the actual method signature and its code, in this method I am simply trying to add values to the dictionary as they come.
public Dictionary<string, string> AddFinesToDictonary(string fineNumber, string errorLine)
{
Dictionary<string, string> erroredLines = new Dictionary<string, string>();
erroredLines.Add(fineNumber, errorLine);
return erroredLines;
}
The only problem that seems to arise here is, only the latest value gets added to the dictionary, meaning the previous added value gets overwritten.
Make erroredLines as global scope.
Dictionary<string, string> erroredLines = new Dictionary<string, string>();
foreach (var line in this.FileLines)
{
count++;
string[] bits = line.Split(',');
fineNumber = bits[0].Trim();
int length = bits.Length;
if (length == 9)
{
//other processing gets done here, code not included as its of no interest for this question
}
else
{
//AddErrorFinesToFile(line, fineNumber);
AddFinesToDictonary(fineNumber, line);
continue;
}
}
public void AddFinesToDictonary(string fineNumber, string errorLine)
{
erroredLines.Add(fineNumber, errorLine);
// return erroredLines;
}
And also no need to return erroredLines dictionary.
What about this;
Dictionary<string, string> erroredLines = new Dictionary<string, string>();
foreach (var line in this.FileLines)
{
count++;
string[] bits = line.Split(',');
fineNumber = bits[0].Trim();
int length = bits.Length;
if (length == 9)
{
//other processing gets done here, code not included as its of no interest for this question
}
else
{
erroredLines.Add(fineNumber, line);
continue;
}
}
after foreach you can use erroredLines dictionary.
The reason is every time you add data to the Directory you create a new one instead of adding data to the exists one
There are two choices you could make:
make a Dictionary out of the function
pass the Dictionary as an out ref to the function
#Hameed Syed 's answer has already given the first one (option 1).
Here is how you could pass the Dictionary as a ref parameter (out) to the function (option 2):
public void AddFinesToDictonary(out Dictionary<string,string>dict, string fineNumber, string errorLine)
{
dict.Add(fineNumber, errorLine);
}
I'm creating a game in Unity3D + C#.
What I've got at the moment: an SQL datatable, consisting of 8 columns holding a total of 3 entries and a list "_WeapList" that holds every entry (as shown below).
public struct data
{
public string Name;
public int ID, dmg, range, magazin, startammo;
public float tbtwb, rltimer;
}
List<data> _WeapList;
public Dictionary<int, data>_WeapoList; //probable change
[...]
//reading the SQL Table + parse it into a new List-entry
while (rdr.Read())
{
data itm = new data();
itm.Name = rdr["Name"].ToString();
itm.ID = int.Parse (rdr["ID"].ToString());
itm.dmg = int.Parse (rdr["dmg"].ToString());
itm.range = int.Parse (rdr["range"].ToString());
itm.magazin = int.Parse (rdr["magazin"].ToString());
itm.startammo = int.Parse (rdr["startammo"].ToString());
itm.tbtwb = float.Parse(rdr["tbtwb"].ToString());
itm.rltimer = float.Parse(rdr["rltimer"].ToString());
_WeapList.Add(itm);
_WeapoList.Add(itm.ID, itm);//probable change
}
Now I want to create a "Weapon"-Class that will have the same 8 fields, feeding them via a given ID
How do I extract the values of a specific item (determined by the int ID, which is always unique) in the list/struct?
public class Weapons : MonoBehaviour
{
public string _Name;
public int _ID, _dmg, _range, _magazin, _startammo;
public float _tbtwb, _rltimer;
void Start()
{//Heres the main problem
_Name = _WeapoList...?
_dmg = _WeapoList...?
}
}
If your collection of weapons may become quite large or you need to frequently look up weapons in it, I would suggest using a Dictionary instead of a List for this (using the weapon ID as the key). A lookup will be much quicker using a Dictionary key than searching through a List using a loop or LINQ.
You can do this by modifying your code to do this as follows:
public Dictionary<int, data>_WeapList;
[...]
//reading the SQL Table + parse it into a new List-entry
while (rdr.Read())
{
data itm = new data();
itm.Name = rdr["Name"].ToString();
itm.ID = int.Parse (rdr["ID"].ToString());
itm.dmg = int.Parse (rdr["dmg"].ToString());
itm.range = int.Parse (rdr["range"].ToString());
itm.magazin = int.Parse (rdr["magazin"].ToString());
itm.startammo = int.Parse (rdr["startammo"].ToString());
itm.tbtwb = float.Parse(rdr["tbtwb"].ToString());
itm.rltimer = float.Parse(rdr["rltimer"].ToString());
_WeapList.Add(itm.ID, itm);//probable change
}
Then, to access elements on the list, just use the syntax:
_WeapList[weaponID].dmg; // To access the damage of the weapon with the given weaponID
Guarding against invalid IDs:
If there's a risk of the weaponID supplied not existing, you can use the .ContainsKey() method to check for it first before trying to access its members:
if (_WeapList.ContainsKey(weaponID))
{
// Retrieve the weapon and access its members
}
else
{
// Weapon doesn't exist, default behaviour
}
Alternatively, if you're comfortable using out arguments, you can use .TryGetValue() instead for validation - this is even quicker than calling .ContainsKey() separately:
data weaponData;
if (_WeapList.TryGetValue(weaponID, out weaponData))
{
// weaponData is now populated with the weapon and you can access members on it
}
else
{
// Weapon doesn't exist, default behaviour
}
Hope this helps! Let me know if you have any questions.
Let specificWeapon be a weapon to be searched in the list, then you can use the following code to select that item from the list of weapons, if it is not found then nullwill be returned. Hope that this what you are looking for:
var selectedWeapon = WeapList.FirstOrDefault(x=> x.ID == specificWeapon.ID);
if(selectedWeapon != null)
{
// this is your weapon proceed
}
else
{
// not found your weapon
}
You can use LINQ to search specific object through weaponId
var Weapon = _WeapList.FirstOrDefault(w=> w.ID == weaponId);
I am trying to parse a rather long log file and creating a better more manageable listing of issues.
I am able to read and parse out the individual log line by line, but what I need to do is display only unique entries, as some errors occur more often than others and are always recorded with identical text.
What I was going to try to do was create a Dictionary object to hold each unique entry and as I work through the log file, search the Dictionary object to see if the same values are already in there.
Here is a crude sample of the code I have (a work in progress, I hope I have all syntax right) that does not work. For some reason this script never sees any distinct entries (if statement never passes):
string[] rowdta = new string[4];
Dictionary<string[], int> dict = new Dictionary<string[], int>();
int ctr = -1;
if (linectr == 1)
{
ctr++;
dict.Add(rowdta, ctr);
}
else
{
foreach (KeyValuePair<string[], int> pair in dict)
{
if ((pair.Key[1] != rowdta[1]) || (pair.Key[2] != rowdta[2])| (pair.Key[3] != rowdta[3]))
{
ctr++;
dict.Add(rowdta, ctr);
}
}
}
Some sample data:
First line
rowdta[0]="ErrorType";
rowdta[1]="Undefined offset: 0";
rowdta[2]="/url/routesDisplay2.svc.php";
rowdta[3]="Line Number 5";
2nd line
rowdta[0]="ErrorType";
rowdta[1]="Undefined offset: 0";
rowdta[2]="/url/routesDisplay2.svc.php";
rowdta[3]="Line Number 5";
3rd line
rowdta[0]="ErrorType";
rowdta[1]="Undefined variable: fvmsg";
rowdta[2]="/url/processes.svc.php";
rowdta[3]="Line Number 787";
So, with this, the Dictionary will have 2 items in it, first line and 3rd line.
I have also tried this with the following which nalso does not find any variations in the log file text.
if (!dict.ContainsKey(rowdta)) {}
Can someone please help me get this syntax right? I am just a newbie at C# but this should be relatively straightforward. As always, I am thinking that this should be enough information to get the conversation started. If you want/need more detail, please let me know.
Either create a wrapper for your strings which implements IEquatable.
public class LogFileEntry :IEquatable<LogFileEntry>
{
private readonly string[] _rows;
public LogFileEntry(string[] rows)
{
_rows = rows;
}
public override int GetHashCode()
{
return
_rows[0].GetHashCode() << 3 |
_rows[2].GetHashCode() << 2 |
_rows[1].GetHashCode() << 1 |
_rows[0].GetHashCode();
}
#region Implementation of IEquatable<LogFileEntry>
public override bool Equals(Object obj)
{
if (obj == null)
return base.Equals(obj);
return Equals(obj as LogFileEntry);
}
public bool Equals(LogFileEntry other)
{
if(other == null)
return false;
return _rows.SequenceEqual(other._rows);
}
#endregion
}
Then use that in your dictionary:
var d = new Dictionary<LogFileEntry, int>();
var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
d[entry] ++;
}
else
{
d[entry] = 1;
}
Or create a custom comparer similar to that proposed by #dasblinkenlight and use as follows
public class LogFileEntry
{
}
public class LogFileEntryComparer : IEqualityComparer<LogFileEntry>{ ... }
var d = new Dictionary<LogFileEntry, int>(new LogFileEntryComparer());
var entry = new LogFileEntry(rows);
if( d.ContainsKey(entry) )
{
d[entry] ++;
}
else
{
d[entry] = 1;
}
The reason that you see the problem is that an array of strings cannot be used as a key in a dictionary without supplying a custom IEqualityComparer<string[]> or writing a wrapper around it.
EDIT Here is a quick and dirty implementation of a custom comparer:
private class ArrayEq<T> : IEqualityComparer<T[]> {
public bool Equals(T[] x, T[] y) {
return x.SequenceEqual(y);
}
public int GetHashCode(T[] obj) {
return obj.Sum(o => o.GetHashCode());
}
}
Here is how you can use it:
var dd = new Dictionary<string[], int>(new ArrayEq<string>());
dd[new[] { "a", "b" }] = 0;
dd[new[] { "a", "b" }]++;
dd[new[] { "a", "b" }]++;
Console.WriteLine(dd[new[] { "a", "b" }]);
The problem is that array equality is reference equality. In other words, it does not depend on the values stored in the array, it depends only on the identity of the array.
Some solutions
use Tuple to hold the row data
use an anonymous type to hold the row data
create a custom type to hold the row data, and, if it is a class, override Equals and GetHashCode.
create a custom implementation of IEqualityComparer to compare the arrays according to their values, and pass that to the dictionary when you create it.