How do I print output in a certain way - c#

I have written this code using LINQ query
static public void BracesRule(String input)
{
//Regex for Braces
string BracesRegex = #"\{|\}";
Dictionary<string, string> dictionaryofBraces = new Dictionary<string, string>()
{
//{"String", StringRegex},
//{"Integer", IntegerRegex },
//{"Comment", CommentRegex},
//{"Keyword", KeywordRegex},
//{"Datatype", DataTypeRegex },
//{"Not included in language", WordRegex },
//{"Identifier", IdentifierRegex },
//{"Parenthesis", ParenthesisRegex },
{"Brace", BracesRegex },
//{"Square Bracket", ArrayBracketRegex },
//{"Puncuation Mark", PuncuationRegex },
//{"Relational Expression", RelationalExpressionRegex },
//{"Arithmetic Operator", ArthimeticOperatorRegex },
//{"Whitespace", WhitespaceRegex }
};
var matches = dictionaryofBraces.SelectMany(a => Regex.Matches(input, a.Value)
.Cast<Match>()
.Select(b =>
new
{
Index = b.Index,
Value = b.Value,
Token = a.Key
}))
.OrderBy(a => a.Index).ToList();
for (int i = 0; i < matches.Count; i++)
{
if (i + 1 < matches.Count)
{
int firstEndPos = (matches[i].Index + matches[i].Value.Length);
if (firstEndPos > matches[(i + 1)].Index)
{
matches.RemoveAt(i + 1);
i--;
}
}
}
foreach (var match in matches)
{
Console.WriteLine(match);
}
}
it's output is something like this
{Index=0, Value= {, Token=Brace}
But I want Output be like
{ BRACE

One possibility would be to modify the anonymous object - create the string from the Key(=Brace) and the Value(={ or }):
string input = "ali{}";
//Regex for Braces
string BracesRegex = #"\{|\}";
Dictionary<string, string> dictionaryofBraces = new Dictionary<string, string>()
{
{"Brace", BracesRegex }
};
var matches = dictionaryofBraces.SelectMany(a => Regex.Matches(input, a.Value)
.Cast<Match>()
.Select(b => String.Format("{0} {1}", b.Value, a.Key.ToUpper())))
.OrderBy(a => a).ToList();
foreach (var match in matches)
{
Console.WriteLine(match);
}
The output is as desired:
{ BRACE
} BRACE

Related

How to get except between two Dictionaries<int, IEnumerable<string>>?

I have two Dictionaries>
var test1 = await GetTest1();
var test2 = await GetTest2();
var groupedTest1 = test1.GroupBy(j => j.someField1)
.ToDictionary(k => k.Key, d => d.Select(s => s.someField2));
var groupedTest2 = test2.GroupBy(a => a.someField1)
.ToDictionary(k => k.Key, d => d.Select(s => s.someField2));
And I need two get the difference between them.
For example:
var result = groupedTest1.Except(groupedTest2);
If groupedTest1 contains something IEnumerable which contains in groupedTest2 I don't need to include this. Besides, I need to include check only for a similar key. My question is:
How can I do it?
groupedTest1 : { { Key: 1, IEnumerable: "test1, test2" },
{ Key: 2, IEnumerable: "test3, test4" } } groupedTest2 : {
{ Key: 2, IEnumerable: "test3, test4" } }
result should be Key: 1, IEnumerable: "test1, test2"
If I understand it you effectively have 2 actions; first, get all the keys that don't match and their entire entry should be in the result, and second for matching keys only get the values that don't match. I've put together a little console app to display this:
static void Main(string[] args)
{
//2 test dictionaries. Key 1 and it's values should be displayed and Key 3 with only "test5".
var test1 = new Dictionary<int, IEnumerable<string>>
{
{ 1, new List<string>{ "test1", "test2" } },
{ 2, new List<string>{ "test3", "test4" } },
{ 3, new List<string>{ "test3", "test4", "test5" } }
};
var test2 = new Dictionary<int, IEnumerable<string>>
{
{ 2, new List<string>{ "test3", "test4" } },
{ 3, new List<string>{ "test3", "test4" } }
};
//get non-matching keys first.
Console.WriteLine("Non-matching keys:");
var entriesWithNoMatch = test1.Where(x => !test2.ContainsKey(x.Key));
foreach (var entry in entriesWithNoMatch)
{
WriteResults(entry.Key, entry.Value.ToList());
}
//get matching keys and compare values
Console.WriteLine("Matching keys, non-matching values:");
var matchingKeys = test1.Keys.Intersect(test2.Keys);
foreach (var match in matchingKeys)
{
var result = new KeyValuePair<int, IEnumerable<string>>(match, test1[match].Except(test2[match]));
if (result.Value.Count() > 0)
{
WriteResults(match, result.Value.ToList());
}
}
Console.ReadLine();
}
//simple method to loop through results displaying key and results.
static void WriteResults(int key, IList<string> results)
{
var sb = new StringBuilder();
foreach (var r in results)
{
sb.Append(r + ",");
}
if (sb.Length > 1)
{
sb.Remove(sb.Length - 1, 1);
}
Console.WriteLine("Key: " + key.ToString() + ", results: " + sb.ToString());
sb.Clear();
}
Results:

Splitting text and putting it into dictionary

I have text with 600 words and I'm supposed to delete every quotation marks, numbers(years, dates, ..), digits ,... I should only have words, and I have to put in into dictionary.
So I have tried to go through with for each loop and get the first letter and save it in a list. Then I split every row in a word.
e.g.:
You are pretty.
You
are
pretty
The problem there are words in a row they're still same but they shouldn't be same. I've tried to fix it but I couldn't find any solution.
public Dictionary<string, int> words = new Dictionary<string, int>();
public Dictionary<char, List<string>> firstletter = new Dictionary<char, List<string>>();
public Aufgabe(string filename)
{
string filler = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ";
foreach (char f in filler)
{
firstletter[f] = new List<string>();
}
Load(filename);
}
public void Load(string filename)
{
List<string> w = new List<string>();
StreamReader r = new StreamReader(filename);
while (!r.EndOfStream)
{
string row = r.ReadLine();
string[] parts = row.Split(' ');
string[] sonderzeichen = new string[] { "#", ",", ".", ";", "'", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "(", ")", "{",
"}", "!", "?", "/", "\"", "&", "+", "-", "–" };
string[] list = new string[parts.Length];
for (int i = 0; i < parts.Length; i++)
{
string a = parts[i];
foreach (string s in sonderzeichen)
{
if (s != "-")
{
a = a.Replace(s, string.Empty);
}
else
{
if (a.Length == 1)
{
a = string.Empty;
}
}
}
list[i] = a;
}
parts = list;
foreach (string a in parts)
{
if (words.ContainsKey(a))
{
words[a] += 1;
}
else
{
words.Add(a, 1);
}
string b = a.ToUpper();
if (b == "")
continue;
List<string> letter = firstletter[b[0]];
if (!letter.Contains(a))
{
letter.Add(a);
}
}
}
}
There are some things missing in the other answers:
No validation is done to check if the text is a word
Comparison should not be case-sensitive (i.e. spain, Spain and SPAIN should be considered the same word)
My solution:
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
string text = "The 'rain' in spain falls mainly on the plain. 07 November 2018 20:02:07 - 20180520 I said the Plain in SPAIN. 12345";
var dictionary = Regex.Split(text, #"\W+")
.Where(IsValidWord)
.GroupBy(m => m, comparer)
.ToDictionary(m => m.Key, m => m.Count(), comparer);
Method IsValidWord:
// logic to validate word goes here
private static bool IsValidWord(string text)
{
double value;
bool isNumeric = double.TryParse(text, out value);
// add more validation rules here
return !isNumeric;
}
EDIT
I noticed in your code that you have a Dictionary with the words grouped by first letter. This can be achieved like this (using the previous dictionary):
var lettersDictionary = dictionary.Keys.GroupBy(x => x.Substring(0, 1),
(alphabet, subList) => new {
Alphabet = alphabet,
SubList = subList.OrderBy(x => x, comparer).ToList()
})
.ToDictionary(m => m.Alphabet, m => m.SubList, comparer);
You can just split with a regex, then use LINQ to create your dictionary:
var dictionary = Regex.Split(text, #"\W+")
.GroupBy(m => m, StringComparer.OrdinalIgnoreCase) // Case-insensitive
.ToDictionary(m => m.Key, m => m.Count());
UPDATE
In applying to your example code, your task class could become something like this to build both dictionaries (and to consider case insensitive):
public class Aufgabe
{
const string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ";
public Dictionary<string, int> words;
public Dictionary<char, List<string>> firstletter;
public Aufgabe(string filename)
{
var text = File.ReadAllText(filename);
words = Regex.Split(text, #"\W+")
.GroupBy(m => m, StringComparer.OrdinalIgnoreCase)
.ToDictionary(m => m.Key, m => m.Count());
firstletter = ALPHABET.ToDictionary(a => a, // First-letter key
a => words.Keys.Where(m => a == char.ToUpper(m[0])).ToList()); // Words
}
}
Here is one way with Regex, note that case sensitivity has not been addressed
var text = "The 'rain' in spain falls mainly on the plain. I said the plain in spain";
var result = new Dictionary<string,string>();
Regex.Matches(text, #"[^\s]+")
.OfType<Match>()
.Select(m => Regex.Replace(m.Value, #"\W", string.Empty))
.ToList()
.ForEach(word =>
{
if (!result.ContainsKey(word))
result.Add(word, word);
});
result
This is almost certainly a job for regular expressions. \W+ splits your input string into words, defined as any character sequence of alphanumeric characters. See the documentation.
string sentence = "You are pretty. State-of-the-art.";
string[] words = Regex.Split(sentence, #"\W+");
foreach (string word in words)
{
if (word != "")
{
Console.WriteLine(word);
}
}

jtoken.selecttokens issue when comparing value of one array with another array

i need to fetch amount using following logic. if product.ID equals stores.ID then fetch product.amount
Json
{
"stores": [
{
"ID": 17736791,
"Name": "ABC"
},
{
"ID": 154423041,
"Name": "XYZ"
}
],
"product": [
{
"ID": 154423041,
"Amount": 19865337
}
]
}
i am using jtoken.selecttoken to fetch data as below. but it throws error as could not read query operator.
string path = ToJsonPath(product[ID=stores[*].ID].Amount);
var data= token.SelectTokens(path)
Updated, ToJsonPath
public string ToJsonPath(string query)
{
string normalizedQuery = query.Replace(DoubleQuotes, SingleQuotes);
StringBuilder jsonPath = new StringBuilder();
jsonPath.Append(string.Concat(RootElement, ChildOperator));
jsonPath.Append(normalizedQuery);
MatchCollection expressions = Regex.Matches(normalizedQuery, ExpressionRegexPattern);
StringBuilder expression = new StringBuilder();
for (int i = 0; i < expressions.Count; i++)
{
if (!Regex.IsMatch(expressions[i].Value, OperatorRegexPattern))
{
continue;
}
expression.Length = 0;
expression.Capacity = 0;
expression.Append(expressions[i].Value);
jsonPath.Replace(expression.ToString(), Placeholder);
string[] expressionTerms = expression.ToString()
.Split(new[] { AndOperator, OrOperator }, StringSplitOptions.RemoveEmptyEntries)
.Select(t => t.Trim())
.ToArray();
foreach (string expressionTerm in expressionTerms)
{
expression.Replace(expressionTerm, Placeholder);
expression.Replace(Placeholder, string.Concat(CurrentElement, ChildOperator, expressionTerm));
}
string expressionWithEscapedOperators = Regex.Replace(expression.ToString(), OperatorRegexPattern, " $& ");
string expressionWithDoubleEqualOperators = Regex.Replace(expressionWithEscapedOperators, EqualOperatorPattern, "$&$&");
string jsonExpression = string.Format(JsonExpressionTemplate, expressionWithDoubleEqualOperators);
jsonPath.Replace(Placeholder, jsonExpression);
}
return jsonPath.ToString();
}
Not sure about JSONPath but with LINQ to JSON this can be achieved as follows:
var obj = JObject.Parse(json);
var storeIds = obj["stores"]
.Select(s => (int)s["ID"])
.ToList();
var selectedAmount = obj["product"]
.Where(p => storeIds.Contains((int)p["ID"]))
.Select(p => (int)p["Amount"])
.FirstOrDefault();
Demo: https://dotnetfiddle.net/CRn5Az

C# : Merging Dictionary and List

I have a List of String like
List<String> MyList=new List<String>{"A","B"};
and a
Dictionary<String, Dictionary<String,String>> MyDict=new Dictionary<String,Dictionary<String,String>>();
which contains
Key Value
Key Value
"ONE" "A_1" "1"
"A_2" "2"
"X_1" "3"
"X_2" "4"
"B_1" "5"
"TWO" "Y_1" "1"
"B_9" "2"
"A_4" "3"
"B_2" "6"
"X_3" "7"
I need to merge the the list and Dictionary into a new Dictionary
Dictionary<String,String> ResultDict = new Dictionary<String,String>()
The resulting dictionary contains
Key Value
"A_1" "1"
"A_2" "2"
"B_1" "5"
"A_4" "3"
"B_2" "6"
"X_2" "4"
"X_3" "7"
Merge rule
First add the items which has a substring equals to any item in the list.
Then Merge the items in the "MyDict" so the result should not contain duplicate keys as well as duplicate values.
Here is my source code.
Dictionary<String, String> ResultDict = new Dictionary<string, string>();
List<String> TempList = new List<string>(MyDict.Keys);
for (int i = 0; i < TempList.Count; i++)
{
ResultDict = ResultDict.Concat(MyDict[TempList[i]])
.Where(TEMP => MyList.Contains(TEMP.Key.Contains('_') == true ? TEMP.Key.Substring(0, TEMP.Key.LastIndexOf('_'))
: TEMP.Key.Trim()))
.ToLookup(TEMP => TEMP.Key, TEMP => TEMP.Value)
.ToDictionary(TEMP => TEMP.Key, TEMP => TEMP.First())
.GroupBy(pair => pair.Value)
.Select(group => group.First())
.ToDictionary(pair => pair.Key, pair => pair.Value); }
for (int i = 0; i < TempList.Count; i++)
{
ResultDict = ResultDict.Concat(MyDict[TempList[i]])
.ToLookup(TEMP => TEMP.Key, TEMP => TEMP.Value)
.ToDictionary(TEMP => TEMP.Key, TEMP => TEMP.First())
.GroupBy(pair => pair.Value)
.Select(group => group.First())
.ToDictionary(pair => pair.Key, pair => pair.Value);
}
its working fine, but I need to eliminate the two for loops or at least one
(Any way to do this using LINQ or LAMBDA expression)
Here's one way you could do it with LINQ and lambdas, as requested:
var keysFromList = new HashSet<string>(MyList);
var results =
MyDict.Values
.SelectMany(x => x)
.OrderBy(x => {
int i = x.Key.LastIndexOf('_');
string k = (i < 0) ? x.Key.Trim()
: x.Key.Substring(0, i);
return keysFromList.Contains(k) ? 0 : 1;
})
.Aggregate(new {
Results = new Dictionary<string, string>(),
Values = new HashSet<string>()
},
(a, x) => {
if (!a.Results.ContainsKey(x.Key)
&& !a.Values.Contains(x.Value))
{
a.Results.Add(x.Key, x.Value);
a.Values.Add(x.Value);
}
return a;
},
a => a.Results);
Loop wise this code is simpler, but not Linq:
public static Dictionary<string, string> Test()
{
int initcount = _myDict.Sum(keyValuePair => keyValuePair.Value.Count);
var usedValues = new Dictionary<string, string>(initcount); //reverse val/key
var result = new Dictionary<string, string>(initcount);
foreach (KeyValuePair<string, Dictionary<string, string>> internalDicts in _myDict)
{
foreach (KeyValuePair<string, string> valuePair in internalDicts.Value)
{
bool add = false;
if (KeyInList(_myList, valuePair.Key))
{
string removeKey;
if (usedValues.TryGetValue(valuePair.Value, out removeKey))
{
if (KeyInList(_myList, removeKey)) continue;
result.Remove(removeKey);
}
usedValues.Remove(valuePair.Value);
add = true;
}
if (!add && usedValues.ContainsKey(valuePair.Value)) continue;
result[valuePair.Key] = valuePair.Value;
usedValues[valuePair.Value] = valuePair.Key;
}
}
return result;
}
private static bool KeyInList(List<string> myList, string subKey)
{
string key = subKey.Substring(0, subKey.LastIndexOf('_'));
return myList.Contains(key);
}

How to split string into a dictionary

I have this string
string sx="(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
and am splitting it with
string [] ss=sx.Split(new char[] { '(', ')' },
StringSplitOptions.RemoveEmptyEntries);
Instead of that, how could I split the result into a Dictionary<string,string>? The
resulting dictionary should look like:
Key Value
colorIndex 3
font.family Helvetica
font.bold 1
It can be done using LINQ ToDictionary() extension method:
string s1 = "(colorIndex=3)(font.family=Helvicta)(font.bold=1)";
string[] t = s1.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
Dictionary<string, string> dictionary =
t.ToDictionary(s => s.Split('=')[0], s => s.Split('=')[1]);
EDIT: The same result can be achieved without splitting twice:
Dictionary<string, string> dictionary =
t.Select(item => item.Split('=')).ToDictionary(s => s[0], s => s[1]);
There may be more efficient ways, but this should work:
string sx = "(colorIndex=3)(font.family=Helvicta)(font.bold=1)";
var items = sx.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Split(new[] { '=' }));
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (var item in items)
{
dict.Add(item[0], item[1]);
}
Randal Schwartz has a rule of thumb: use split when you know what you want to throw away or regular expressions when you know what you want to keep.
You know what you want to keep:
string sx="(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
Regex pattern = new Regex(#"\((?<name>.+?)=(?<value>.+?)\)");
var d = new Dictionary<string,string>();
foreach (Match m in pattern.Matches(sx))
d.Add(m.Groups["name"].Value, m.Groups["value"].Value);
With a little effort, you can do it with ToDictionary:
var d = Enumerable.ToDictionary(
Enumerable.Cast<Match>(pattern.Matches(sx)),
m => m.Groups["name"].Value,
m => m.Groups["value"].Value);
Not sure whether this looks nicer:
var d = Enumerable.Cast<Match>(pattern.Matches(sx)).
ToDictionary(m => m.Groups["name"].Value,
m => m.Groups["value"].Value);
string sx = "(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
var dict = sx.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Split('='))
.ToDictionary(x => x[0], y => y[1]);
var dict = (from x in s1.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
select new { s = x.Split('=') }).ToDictionary(x => x[0], x => x[1]);
Often used for http query splitting.
Usage: Dictionary<string, string> dict = stringToDictionary("userid=abc&password=xyz&retain=false");
public static Dictionary<string, string> stringToDictionary(string line, char stringSplit = '&', char keyValueSplit = '=')
{
return line.Split(new[] { stringSplit }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Split(new[] { keyValueSplit })).ToDictionary(x => x[0], y => y[1]); ;
}
You can try
string sx = "(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
var keyValuePairs = sx.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
.Select(v => v.Split('='))
.ToDictionary(v => v.First(), v => v.Last());
You could do this with regular expressions:
string sx = "(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
Dictionary<string,string> dic = new Dictionary<string,string>();
Regex re = new Regex(#"\(([^=]+)=([^=]+)\)");
foreach(Match m in re.Matches(sx))
{
dic.Add(m.Groups[1].Value, m.Groups[2].Value);
}
// extract values, to prove correctness of function
foreach(var s in dic)
Console.WriteLine("{0}={1}", s.Key, s.Value);
I am just putting this here for reference...
For ASP.net, if you want to parse a string from the client side into a dictionary this is handy...
Create a JSON string on the client side either like this:
var args = "{'A':'1','B':'2','C':'" + varForC + "'}";
or like this:
var args = JSON.stringify(new { 'A':1, 'B':2, 'C':varForC});
or even like this:
var obj = {};
obj.A = 1;
obj.B = 2;
obj.C = varForC;
var args = JSON.stringify(obj);
pass it to the server...
then parse it on the server side like this:
JavaScriptSerializer jss = new JavaScriptSerializer();
Dictionary<String, String> dict = jss.Deserialize<Dictionary<String, String>>(args);
JavaScriptSerializer requires System.Web.Script.Serialization.

Categories