C# String Pattern Matching - c#

I have 2 lists of strings in C# showing the players who have joined and left a particular game. I'm trying to attempt to determine who is still in the game by matching both lists and eliminating the entries of those who have left the game. Please suggest a easy and pain free algorithm to go about doing this. My current code is as follows
string input = inputTextBox.Text;
string[] lines = input.Split(new string[] {"\r\n", "\n"}, StringSplitOptions.None);
List<string> filteredinput = new List<string>();
List<string> joinedlog = new List<string>();
List<string> leftlog = new List<string>();
for (int i = 0; i<lines.Length; i++)
{
if (lines[i].Contains("your game!"))
filteredinput.Add(lines[i]);
}
for (int i =0; i<filteredinput.Count; i++)
{
if (filteredinput[i].Contains("joined"))
joinedlog.Add(filteredinput[i]);
else if (filteredinput[i].Contains("left"))
leftlog.Add(filteredinput[i]);
}
Here is some sample input :
{SheIsSoScrewed}[Ping:|] has joined your game!.
{AngeLa_Yoyo}[Ping:X] has joined your game!.
{SheIsSoScrewed} has left your game!(4).

Are you asking how to get your two lists, or how to find the current players after you've already got the two lists?
The second part can be done with Linq....
List<string> joinedGame;
List<string> leftGame;
List<string> currentInGame
= joinedGame.Where(x => !leftGame.Contains(x)).ToList();
EDIT In response to your comment, having read your question again then obviously the above won't work because you are building your lists in a weird way.
You are storing the whole string in the list, e.g. user_1 has left the game, what you should probably be doing is just storing the user name. If you correct this then the above code does exactly what you want.
A full example:
var input = new List<string>()
{
"user_1 has joined the game",
"user_2 has joined the game",
"user_1 has left the game",
"user_3 has joined the game"
};
var joined = new List<string>();
var left = new List<string>();
foreach(string s in input)
{
var idx = s.IndexOf(" has joined the game");
if (idx > -1)
{
joined.Add(s.Substring(0, idx));
continue;
}
idx = s.IndexOf(" has left the game");
if (idx > -1)
{
left.Add(s.Substring(0, idx));
}
}
var current = joined.Where(x => !left.Contains(x)).ToList();
foreach(string user in current)
{
Console.WriteLine(user + " is still in the game");
}

Intersect and Except are your friends.
Also, if this is the sole purpose of the lists, consider using something like HashSet instead.

How about using List.Find() ?
Link 1 here
Link 2 here

use linq and regex:
var join=new Regex("joined.*?your game");
var joinLog = (from l in lines where join.IsMatch(join) select l).ToList();
var left=new Regex("left.*?your game");
var leftLog = (from l in lines where left.IsMatch(join) select l).ToList();

First you need to extract the player names so you can calculate the difference:
var join=new Regex("{(.*)}[.*joined.*?your game");
var joinedNames = filteredinput.Select(l => join.Match(l)).Where(m => m.Success).Select(m => m.Groups[1]).Distinct();
var left=new Regex("{(.*)}[.*left.*?your game");
var leftNames = filteredinput.Select(l => left.Match(l)).Where(m => m.Success).Select(m => m.Groups[1]).Distinct();
Now calculate the difference:
var playersStillInGame = joinedNames.Except(leftNames);

string input = inputTextBox.Text;
string[] lines = input.Split(new string[] {"\r\n", "\n"}, StringSplitOptions.None);
Regex joinedLeft = new Regex(#"\{([^{}]*)}.*? has (joined|left) your game!");
HashSet<string> inGame = new HashSet<string>();
foreach (string line in lines)
{
Match match = joinedLeft.Match(line);
if (!match.Success)
continue;
string name = match.Groups[1].Value;
string inOrOut = match.Groups[2].Value;
if (inOrOut == "joined")
inGame.Add(name);
else
inGame.Remove(name);
}

Related

How can I split a string to store contents in two different arrays in c#?

The string I want to split is an array of strings.
the array contains strings like:
G1,Active
G2,Inactive
G3,Inactive
.
.
G24,Active
Now I want to store the G's in an array, and Active or Inactive in a different array. So far I have tried this which has successfully store all the G's part but I have lost the other part. I used Split fucntion but did not work so I have tried this.
int i = 0;
for(i = 0; i <= grids.Length; i++)
{
string temp = grids[i];
temp = temp.Replace(",", " ");
if (temp.Contains(' '))
{
int index = temp.IndexOf(' ');
grids[i] = temp.Substring(0, index);
}
//System.Console.WriteLine(temp);
}
Please help me how to achieve this goal. I am new to C#.
If I understand the problem correctly - we have an array of strings Eg:
arrayOfStrings[24] =
{
"G1,Active",
"G2,Inactive",
"G3,Active",
...
"G24,Active"
}
Now we want to split each item and store the g part in one array and the status into another.
Working with arrays the solution is to - traverse the arrayOfStrings.
Per each item in the arrayOfStrings we split it by ',' separator.
The Split operation will return another array of two elements the g part and the status - which will be stored respectively into distinct arrays (gArray and statusArray) for later retrieval. Those arrays will have a 1-to-1 relation.
Here is my implementation:
static string[] LoadArray()
{
return new string[]
{
"G1,Active",
"G2,Inactive",
"G3,Active",
"G4,Active",
"G5,Active",
"G6,Inactive",
"G7,Active",
"G8,Active",
"G9,Active",
"G10,Active",
"G11,Inactive",
"G12,Active",
"G13,Active",
"G14,Inactive",
"G15,Active",
"G16,Inactive",
"G17,Active",
"G18,Active",
"G19,Inactive",
"G20,Active",
"G21,Inactive",
"G22,Active",
"G23,Inactive",
"G24,Active"
};
}
static void Main(string[] args)
{
string[] myarrayOfStrings = LoadArray();
string[] gArray = new string[24];
string[] statusArray = new string[24];
int index = 0;
foreach (var item in myarrayOfStrings)
{
var arraySplit = item.Split(',');
gArray[index] = arraySplit[0];
statusArray[index] = arraySplit[1];
index++;
}
for (int i = 0; i < gArray.Length; i++)
{
Console.WriteLine("{0} has status : {1}", gArray[i] , statusArray[i]);
}
Console.ReadLine();
}
seems like you have a list of Gxx,Active my recomendation is first of all you split the string based on the space, which will give you the array previoulsy mentioned doing the next:
string text = "G1,Active G2,Inactive G3,Inactive G24,Active";
string[] splitedGItems = text.Split(" ");
So, now you have an array, and I strongly recommend you to use an object/Tuple/Dictionary depends of what suits you more in the entire scenario. for now i will use Dictionary as it seems to be key-value
Dictionary<string, string> GxListActiveInactive = new Dictionary<string, string>();
foreach(var singleGItems in splitedGItems)
{
string[] definition = singleGItems.Split(",");
GxListActiveInactive.Add(definition[0], definition[1]);
}
What im achiving in this code is create a collection which is key-value, now you have to search the G24 manually doing the next
string G24Value = GxListActiveInactive.FirstOrDefault(a => a.Key == "G24").Value;
just do it :
var splitedArray = YourStringArray.ToDictionary(x=>x.Split(',')[0],x=>x.Split(',')[1]);
var gArray = splitedArray.Keys;
var activeInactiveArray = splitedArray.Values;
I hope it will be useful
You can divide the string using Split; the first part should be the G's, while the second part will be "Active" or "Inactive".
int i;
string[] temp, activity = new string[grids.Length];
for(i = 0; i <= grids.Length; i++)
{
temp = grids[i].Split(',');
grids[i] = temp[0];
activity[i] = temp[1];
}

MVC .NET OrWhere Query

I want to perform a query on a list of words.
string[] words = {"word1", "word2", "word3"}
In my database I have a list of tracks with artist and titles. I want to concatenate all the queries with OrWhere conditions.
This is what I have for the moment :
var word;
var queryTracks;
for (int i = 0; i < words.Length; i++)
{
word = words[i];
queryTracks = db.Tracks.Where(c => c.Title.Contains(word) || c.Artist.Contains(word));
}
// all found, put all that into a list
var filteredTracks = queryTracks.ToList();
I already tried with the .Concat() method like this :
var word = words[0];
var queryTracks = db.Tracks.Where(c => c.Title.Contains(word) || c.Artist.Contains(word));;
for (int i = 1; i < words.Length; i++)
{
word = words[i];
queryTracks = queryTracks.Concat(db.Tracks.Where(c => c.Title.Contains(word) || c.Artist.Contains(word)));
}
But it didn't work... I just want to have all the tracks with word1, word2 and word3. Can I make a big query and then put it into a list or do I have to make list1, list2 and list3 and concatenate them ?
You can use a single query
string[] words = {"word1", "word2", "word3"}
IEnumerable<Track> tracks = db.Tracks.Where(c => words.Contains(c.Title) || words.Contains(c.Artist));

C# compare input with keywords

ive got the following c# code:
string textBoxInput = richTextBox1.Text;
StreamReader SentencesFile = new StreamReader(#"C:\Users\Jeroen\Desktop\School\C#\opwegmetcsharp\answersSen.txt");
string Sentence = SentencesFile.ReadLine();
List<List<string>> keywordsList = new List<List<string>>();
List<string> outputSentence = new List<string>();
while (Sentence != null)
{
string keywords = Sentence.Substring(0, Sentence.IndexOf(' '));
string sentenceString = Sentence.Substring(0, Sentence.IndexOf(' ') +1);
List<string> splitKeyword = keywords.Split(',').ToList();
keywordsList.Add(splitKeyword);
outputSentence.Add(sentenceString);
}
int similar = 0;
int totalSimilar = 0;
List<string> SplitUserInput = textBoxInput.Split(' ').ToList();
And a .txt file which contains the following:
car,bmw Do you own a BMW?
car,Tesla Do you own a Tesla?
new,house Did you buy a new house?
snow,outside Is it snowing outside?
internet,down Is your internet down?
I can't figure out how i can compare every word that a user typed in the input (richTextBox1.Text) with the keywords in the .txt file ( like car and bmw for the first sentence )
And it also has to remember the sentence that has the highest amount of "hits".
I'm really stuck and searched a lot, but somehow i can't find out how i can do this.
A lot of thanks in advance!
You can use the LINQ Contains to check if a word is found in a list. But beware because it is case sensitive as password does. Use it like this:
//assuming you already list the keyword here
List<string> keywords = new List<string>() { "keyword1", "keyword2" };
Then for each sentence, supposing in this form:
string sentence1 = "Hi, this keYWord1 present! But quite malformed";
string sentence2 = "keywoRD2 and keyWOrd1 also present here, malformed";
Note: the above sentences could be your text from RichTextBox or file, it doesn't matter. Here I only show the concept.
You can do:
string[] words = sentence1.ToLower().Split(new char[] { ' ', ',', '.' });
int counter = 0;
for (int i = 0; i < words.Length; ++i){
counter += keywords.Contains(words[i]) ? 1 : 0;
}
And you can do likewise for sentence2. Whoever gets the highest counter has the highest hits.
This might be too advanced for a 1st year student but this piece of code will work for your need. Using Regex class to do matching for you. Performance-wise it's faster (AFAIK). I used a console application to work on this as I don't think it will be hard for you to use it in a WinForms/WPF application.
string textBoxInput = "car test do bmw"; // Just a sample as I am using a console app
string[] sentences = File.ReadAllLines("sentences.txt"); // Read all lines of a text file and assign it to a string array
string[] keywords = textBoxInput.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Split textBoxInput by space
int[] matchArray = new int[sentences.Length];
for(int i = 0; i < sentences.Length; i++)
{
Regex regex = new Regex(#"\b(" + string.Join("|", keywords.Select(Regex.Escape).ToArray()) + #"+\b)", RegexOptions.IgnoreCase);
MatchCollection matches = regex.Matches(sentences[i]);
matchArray[i] = matches.Count;
}
int highesMatchIndex = Array.IndexOf(matchArray, matchArray.OrderByDescending(item => item).First());
Console.WriteLine("User input: " + textBoxInput);
Console.WriteLine("Matching sentence: " + sentences[highesMatchIndex]);
Console.WriteLine("Match count: " + matchArray[highesMatchIndex]);
Console.ReadLine();

Split a string base on multiple delimiters specified by user

Updated: Thank you for the answer, but I disagree that my question is answered by another thread. "Multiple delimiters" and "Multi-Character delimiters" are 2 different questions.
This is my code so far:
List<string> delimiters = new List<string>();
List<string> data = new List<string>
{
"Car|cBlue,Mazda~Model|m3",
//More data
};
string userInput = "";
int i = 1;
//The user can enter a maximum of 5 delimiters
while (userInput != "go" && i <= 5)
{
userInput = Console.ReadLine();
delimiters.Add(userInput);
i++;
}
foreach (string delimiter in delimiters)
{
foreach (string s in data)
{
//This split is not working
//string output[] = s.Split(delimiter);
}
}
So, if the user enters "|c" and "~", the expected output is: "Car", "Blue,Mazda", "Model|m3"
If the user enters "|c", "|m", and ",", then the expected output will be: "Car", "Blue", "Mazda~Model", "3"
Add the user input into the List delimiters.
string data = "Car|cBlue,Mazda~Model|m3";
List<string> delimiters = new List<string>();
delimiters.Add("|c");//Change this to user input
delimiters.Add("|m");//change this to user input
string[] parts = data.Split(delimiters.ToArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (string item in parts)
{
Console.WriteLine(item);
}
String.Split has an overload that does exactly that - you just need to convert your List<string> to a string[] :
string input = "Car|cBlue,Mazda~Model|m3";
List<string> delims = new List<string> {"|c", "~"};
string[] out1 = input.Split(delims.ToArray(),StringSplitOptions.None);
//output:
// Car
// Blue,Mazda
// Model|m3
delims = new List<string> {"|c", "|m", ","};
string[] out2 = input.Split(delims.ToArray(),StringSplitOptions.None).Dump();
//output:
// Car
// Blue
// Mazda~Model
// 3
You can use SelectMany to get the result from all the data strings and ToArray() method to create an array from delimiters
var result = data.SelectMany(s => s.Split(delimiters.ToArray(), StringSplitOptions.None));

Occurence of elements in the file with c# and Dictionary

I have a file as
outlook temperature Humidity Windy PlayTennis
sunny hot high false N
sunny hot high true N
overcast hot high false P
rain mild high false P
rain cool normal false P
rain cool normal true N
I want to find occurence of each element e.g
sunny: 2
rain: 3
overcast:1
hot: 3
and so on
My code is:
string file = openFileDialog1.FileName;
var text1 = File.ReadAllLines(file);
StringBuilder str = new StringBuilder();
string[] lines = File.ReadAllLines(file);
string[] nonempty=lines.Where(s => s.Trim(' ')!="")
.Select(s => Regex.Replace(s, #"\s+", " ")).ToArray();
string[] colheader = null;
if (nonempty.Length > 0)
colheader = nonempty[0].Split();
else
return;
var linevalue = nonempty.Skip(1).Select(l => l.Split());
int colcount = colheader.Length;
Dictionary<string, string> colvalue = new Dictionary<string, string>();
for (int i = 0; i < colcount; i++)
{
int k = 0;
foreach (string[] values in linevalue)
{
if(! colvalue.ContainsKey(values[i]))
{
colvalue.Add(values[i],colheader[i]);
}
label2.Text = label2.Text + k.ToString();
}
}
foreach (KeyValuePair<string, string> pair in colvalue)
{
label1.Text += pair.Key+ "\n";
}
Output I get here is
sunny
overcast
rain
hot
mild
cool
N
P
true
false
I also want to find the occurence, which I am unable to get. Can u please help me out here.
This LINQ query will return Dictionary<string, int> which will contain each word in file as key, and word's occurrences as value:
var occurences = File.ReadAllLines(file).Skip(1) // skip titles line
.SelectMany(l => l.Split(new []{' '}, StringSplitOptions.RemoveEmptyEntries))
.GroupBy(w => w)
.ToDictionary(g => g.Key, g => g.Count());
Usage of dictionary:
int sunnyOccurences = occurences["sunny"];
foreach(var pair in occurences)
label1.Text += String.Format("{0}: {1}\n", pair.Key, pair.Value);
Seems to me like you are implementing a simple Tag Cloud. I have used non-generic collection but you can replace it with generic. Replace the HashTable with Dictionary
Follow this code:
Hashtable tagCloud = new Hashtable();
ArrayList frequency = new ArrayList();
Read from a file and store it as array
string[] lines = File.ReadAllLines("file.txt");
//use the specific delimiter
char[] delimiter = new char[] { ' ' };
StringBuilder buffer = new StringBuilder();
foreach (string line in lines)
{
if (line.ToString().Length != 0)
{
buffer.Append((" " + line.Trim()));
}
}
string[] words = buffer.ToString().Trim().Split(delimiter);
Storing occurrence of each word.
List<string> listOfWords = new List<string>(words);
foreach (string i in listOfWords)
{
int c = 0;
foreach (string j in words)
{
if (i.Equals(j))
c++;
}
frequency.Add(c);
}
Store as key value pair. Value will be word and key will be its occurrence
for (int i = 0; i < listOfWords.Count; i++)
{
//use dictionary here
tagCloud.Add(listOfWords[i], (int)frequency[i]);
}
If all you want is the keyword and a count of how many times they appear in the file, then lazyberezovsky's solution is about as elegant of a solution as you will find. But if you need to do any other metrics on the file's data, then I would load the file into a collection that keeps your other metadata intact.
Something simple like:
var forecasts = File.ReadAllLines(file).Skip(1) // skip the header row
.Select(line => line.Split(new []{' '}, StringSplitOptions.RemoveEmptyEntries)) // split the line into an array of strings
.Select (f =>
new
{
Outlook = f[0],
Temperature = f[1],
Humidity = f[2],
Windy = f[3],
PlayTennis = f[4]
});
will give you an IEnumerable<> of an anonymous type that has properties that can be queried.
For example if you wanted to see how many times "sunny" occurred in the Outlook then you could just use LINQ to do this:
var count = forecasts.Count( f => f.Outlook == "sunny");
Or if you just wanted the list of all outlooks you could write:
var outlooks = forecasts.Select(f => f.Outlook).Distinct();
Where this is useful is when you want to do more complicated queries like "How many rainy cool days are there?
var count = forecasts.Count (f => f.Outlook == "rain" && f.Temperature == "cool");
Again if you just want all words and their occurrence count, then this is overkill.

Categories