I am currently facing an issue where I want to add different values to the same Key in a foreach loop.
List<KeyValuePair<string, Dictionary<string, string>>> sysList = new List<KeyValuePair<string, Dictionary<string, string>>>();
Dictionary<string, string> newSystem = new Dictionary<string, string>();
string line1="";
string line2="";
string quit="";
foreach(Worksheet ws in workbook.Worksheets)
{
while(quit != q)
{
newSystem.Clear();
line1 = Console.ReadLine();
line2 = Console.ReadLine();
quit = Console.ReadLine();
}
newSystem.Add(line1, line2);
sysList.Add(new KeyValuePair<string, Dictionary<string, string>>(ws.Name,newSystem));
}
For the first iteration (within while) of the first Worksheet ws everything is fine. If the I choose to do >1 iterations within this Worksheet, there is a new entry added, but the Dictionary values are all the same, f.e.:
syList[0]: "worksheetName","test1","test2"
syList[1]: "worksheetName","test1","test2"
syList[2]: "worksheetName","test1","test2"
If there are several foreach iterations, the names stay the same, but the Dictionary Key and Values added by newSys are the same [AFTER the second foreach iteration]:
syList[0]: "worksheetName1","test1","test2"
syList[1]: "worksheetName1","test1","test2"
syList[2]: "worksheetName1","test1","test2"
syList[3]: "worksheetName2","test1","test2"
syList[4]: "worksheetName2","test1","test2"
Initially I tried using Dictionaries, but could not handle the same keys properly and did not find a proper solution except for using List.
I am very grateful for any help provided.
If there are additional details that you require, please, let me know.
Edit:
desired result (example):
#########: ws.Name, line1, line2
syList[0]: "worksheetName1","ABC","1"
syList[1]: "worksheetName1","DEF","2"
syList[2]: "worksheetName1","ABC","5"
syList[3]: "worksheetName2","ABD","4"
syList[4]: "worksheetName2","ZZZ","1"
In case you don't want to maintain any uniqueness in the keys and just want a flat list, you can use the C#7 tuple syntax to build your list.
List<string> sheetNames = new List<string>() { "worksheetName1", "worksheetName2" };
var sysList = new List<(string SheetName, string line1, string line2)>();
string line1 = string.Empty;
string line2 = string.Empty;
string quit = string.Empty;
foreach (var sheet in sheetNames)
{
while (quit != "E")
{
line1 = Console.ReadLine();
line2 = Console.ReadLine();
quit = Console.ReadLine();
sysList.Add((sheet, line1, line2));
}
quit = string.Empty;
}
Try code below :
List<List<string>> syList = new List<List<string>>() {
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName2","test1","test2"},
new List<string>() {"worksheetName2","test1","test2"}
};
Dictionary<string, Dictionary<string, List<string>>> dict = syList
.GroupBy(x => x.First(), y => y)
.ToDictionary(x => x.Key, y => y
.GroupBy(a => a.Skip(1).FirstOrDefault(), b => b.Last())
.ToDictionary(a => a.Key, b => b.ToList()));
//using normal looping
Dictionary<string, Dictionary<string, List<string>>> dict2 = new Dictionary<string, Dictionary<string, List<string>>>();
foreach (List<string> sy in syList)
{
if (dict2.ContainsKey(sy[0]))
{
Dictionary<string, List<string>> tempDict = dict2[sy[0]];
if (tempDict.ContainsKey(sy[1]))
{
tempDict[sy[1]].Add(sy[2]);
}
else
{
List<string> newList = new List<string>() { sy[2] };
tempDict.Add(sy[1], newList);
}
}
else
{
Dictionary<string, List<string>> newDict = new Dictionary<string, List<string>>();
newDict.Add(sy[1], new List<string> { sy[2] });
dict2.Add(sy[0], newDict);
}
}
Related
var ctsDB = mooe.Files66.ToList();
Dictionary<string, string> mappedfields = new Dictionary<string, string>();
Dictionary<string, string> ctsfieldsValue = new Dictionary<string, string>();
for (int i = 0; i < ctsDB.Count; i++)
{
foreach(var item in mappedfields) {
// this line returns the item.key string not the value of it.
// item.key is the column name
var rowValue = mooe.Files66.Select(k = >item.Key).ToList();
// ctsfieldsValue.Add(item.Value, rowValue);
ctsfieldsValue.ToList();
}
}
I want to iterate through ctsDB List and get the row value of a specific
column like this:
if ctsDB [i] = fileID Field612 Fiel613
and I have these column names in the value field of ctsfieldsValue.
I want to iterate on ctsDB[i] to get the value of column Field612 only.
Can anyone provide a thought?
var ctsDB = mooe.Files66.ToList();
var mappedfields = new Dictionary<string, string>(); // I assume this is not empty in your real code.
var ctsfieldsValue = new List<Dictionary<string, string>>();
foreach (var row in ctsDB)
{
var d = new Dictionary<string, string>();
foreach (var mapping in mappedfields)
{
var v = row[mapping.Key]; //throws if not found
d[mapping.Value] = v;
}
ctsfieldsValue.Add(d);
}
I have a string output that looks like this:
ID = GC5c.U.feab4bc5-8-92e-c486eaddddf8
AESKEY1 = efbf5c9db259e345c205b0da27f6fb459D
AESKEY2 = ea85af9f1e5f42ff4fe8b9f07e7dcebc68
DESKEY1 = 6388a9e1a2fc8981189f0f412ae4e8
ID = JNPa.T.71664548-82-be2-a51aadd4a6f3
AESKEY1 = 37af9242c8879414e420f46903c16adebd3
AESKEY2 = 1259a1f6f6da03cb3984a117ca617d9ff73
DESKEY1 = 9547dc08db70cb95789f3a59e5c6adebd31
How can I iterate through the ID(s) of this list and obtain the values within the string?
Open the file, iterate through each line, and put it into a Dictionary<string, string>
Dictionary<string, string> data = new Dictionary<string, string>();
using(StreamReader reader = new StreamReader("C:/YourFilePath.txt"))
{
while (reader.Peek() >= 0)
{
string[] line = reader.ReadLine().Split('=');
data.Add(line[0].TrimEnd(), line[1].TrimStart());
}
}
UPDATE: Note that this solution is using Dictionary, and so it does not allow duplicate keys. If you need to duplicate keys, I would suggest changing this solution for a List<KeyValuePair<string, string>>. The code will get a little dirtier by the way:
List<KeyValuePair<string, string>> data = new List<KeyValuePair<string, string>>();
using(StreamReader reader = new StreamReader("C:/YourFilePath.txt"))
{
while (reader.Peek() >= 0)
{
string[] line = reader.ReadLine().Split('=');
data.Add(new KeyValuePair(line[0].TrimEnd(), line[1].TrimStart()));
}
}
I am not sure Regex is the best suited for this scenario, however, please find below a solution using it with a named group "id".
var regex = new Regex(#"id.*=\s*(?<id>.+)", RegexOptions.IgnoreCase);
var input = #"ID = Gs3c.H.feab4bc5-6c00-4ee8-9e2e-c486eaddddf8
AESKEY1 = efbf5c9db259e345c205b0da27f6fb459D
AESKEY2 = ea85af9f1e5f42ff4fe8b9f07e7dcebc68
DESKEY1 = 6388a9e1a2fc8981189f0f412ae4e8
ID = JNPa.T.71664548-82-be2-a51aadd4a6f3
AESKEY1 = 37af9242c8879414e420f46903c16adebd3
AESKEY2 = 1259a1f6f6da03cb3984a117ca617d9ff73
DESKEY1 = 9547dc08db70cb95789f3a59e5c6adebd31";
var ids = regex.Matches(input).Cast<Match>().Select(m => m.Groups["id"]);
Here is the Regex test: Regex test
NicoRiff's suggestion of using regular parsing into a Dictionary is the way to go. Here's the obligatory LINQ-based approach:
var data = File.ReadLines("C:/your/file/path.txt")
.Select(l => l.Split('='))
.ToDictionary(k => k[0], v => v[1]);
EDIT: As Nico pointed out, when the dictionary is going to contain duplicate keys, then a dictionary won't work. However, you can still use LINQ to automatically arrange the dictionary so that the ID field of your source text is the key instead of the field names. For example, you can use the following:
var data = File.ReadLines("C:/your/file/path.txt")
.Where(l => !String.IsNullOrEmpty(l))
.Select((l, i) => new { ID = i / 4, Value = l.Split('=') })
.GroupBy(x => x.ID)
.Select(g => new { ID = g.First().Value[1].Trim(), Values = g.ToDictionary(k => k.Value[0].Trim(), v => v.Value[1].Trim()) })
.ToDictionary(k => k.ID, v => v.Values);
Afterwards, you can iterate through data to get your fields:
foreach (var d in data.Values)
{
string id = d["ID"];
string aesKey1 = d["AESKEY1"];
string aesKey2 = d["AESKEY2"];
string desKey1 = d["DESKEY1"];
}
If you like to put the data into a dictionary like: Dicationary<string, Dictionary<string,string>>
Where the key of the main dictionary is the value of ID, and the internal dictionaries are the values that follows, then the following would do it:
string[] lines = input.Split('\n');
var myDict = new Dictionary<string, Dictionary<string,string>>();
var currentKey = "";
foreach (string[] keyVal in lines.Where(line=>!string.IsNullOrWhiteSpace(line))
.Select(line => line.Split('=')))
{
if (keyVal[0].StartsWith("ID"))
{
currentKey = keyVal[1].Trim();
myDict.Add(currentKey, new Dictionary<string, string>());
}
else
{
myDict[currentKey].Add(keyVal[0].Trim(), keyVal[1].Trim());
}
}
The Regex would look like so:
#"^ID\s+=\s+(.+)$"
You can test it on Regex101 and Rextester
I'm actually trying to check if a string is equal to any of the key's in my Dictionary object.
Here is what I have done so far:
using (var oStreamReader = new StreamReader(path))
{
Dictionary<String, String> typeNames = new Dictionary<string, string>();
typeNames.Add("Kind","nvarchar(1000)");
typeNames.Add("Name","nvarchar(1000)");
DataTable oDataTable = new DataTable();
var headLine = oStreamReader.ReadLine().Trim().Replace("\"", "");
var columnNames = headLine.Split(new[] { ';' });
String[] oStreamDataValues;
/*
*create DataTable header with specific datatypes and names
*/
int countCol = 0;
foreach (string readColumn in columnNames)
{
if ((readColumn.ToString().Replace("\"", "").CompareTo(typeNames) == true))
{
// this comparison doesn't work
}
}
}
I am not quite sure what exactly you are trying to achieve. If you have a C# dictonary you can use linq to check for values that match the required value, e.g.
string valueToCompare = "Value to match";
Dictionary<string, string> dict = new Dictionary<string, string>
{
{"Key 1", "A value"},
{"Key 2", "Another value"}
};
bool found= dict.Values
.Any(value
=>
value.Equals(valueToCompare,
StringComparison.CurrentCultureIgnoreCase)
);
Since you want check if exist an entry in your Dictionary that as the same key of one of the values in your columnNames object I suggest you to use ContainsKey method
Dictionary<string, string> d = new Dictionary<string, string>();
string keyvalue;
if (d.ContainsKey("value to find"))
{
if (d.TryGetValue("value to find", out keyvalue))
{
//// here keyvalue variable has the value
}
else
{
///value is null or throws exception
}
}
else
{
////key no exists
}
I have solved this (by inspiration of Paul Houlston and Thomas Lielacher)
string headLine = oStreamReader.ReadLine().Trim().Replace("\"", "");
string columnNames = headLine.Split(new[] { ';' });
foreach (string readColumn in columnNames)
{
if (typeNames.Keys.Contains(readColumn, StringComparer.CurrentCultureIgnoreCase) == true)
{
DataColumn oDataColumn = new DataColumn(readColumn,typeof(System.String));
oDataTable.Columns.Add(oDataColumn);
}
}
I am working on small utility and as it turns out I have to compare two dictionaries and export the data in Excel in the below format
Key dict1value dict2value
If a key is available in both the dictionaries. My output would be
Key dict1value dict2value
If a key is available in firstdictionary and not in second . My output would be
Key dict1Value "NotAvailable"
If a key is available in second dictionary but not in first . My output would be
key "Not Available" dict2value.
To be more clear, The key column in Excel consists of keys from both the dictionaries.The value columns will have values depending on the availability.
Though the below code is working,I would like to know if I can optimize the performance even more.
Note : Please ignore the bad naming conventions
public void validateTwoDictionaries()
{
Dictionary<string, string> dict1 = new Dictionary<string, string>();
Dictionary<string, string> dict2 = new Dictionary<string, string>();
Dictionary<string, KeyValuePair<string, string>> complexdicts = new Dictionary<string, KeyValuePair<string, string>>();
dict1.Add("A", "1");
dict1.Add("B", "2");
dict2.Add("A", "2");
dict2.Add("C", "3");
dict2.Add("D", "4");
int count1 = dict1.Keys.Count;
int count2 = dict2.Keys.Count;
int maxcount = count2;
if (count1 > count2)
{
maxcount = count1;
}
for (int i = 0; i < maxcount; i++)
{
string dict1Key = string.Empty; string dict2Key = string.Empty;
//need to iterate both the dictionaries at one go.
if (i < count1)
{
dict1Key = dict1.Keys.ElementAt(i);
}
if (i < count2)
{
dict2Key = dict2.Keys.ElementAt(i);
}
// do the work for first dictionary, try to decouple to reuse for the 2nd dict
if (dict1Key != string.Empty)
{
if (!complexdicts.Keys.Contains(dict1Key))
{
if (dict2.Keys.Contains(dict1Key))
{
// Add to the complext dictionary
complexdicts.Add(dict1Key, new KeyValuePair<string, string>(dict1[dict1Key], dict2[dict1Key]));
}
else
{
complexdicts.Add(dict1Key, new KeyValuePair<string, string>(dict1[dict1Key], "Not Available"));
}
}
}
// do the work for second dictionary
if (dict2Key != string.Empty)
{
if (!complexdicts.Keys.Contains(dict2Key))
{
if (dict1.Keys.Contains(dict2Key))
{
// Add to the complext dictionary
complexdicts.Add(dict2Key, new KeyValuePair<string, string>(dict1[dict2Key], dict2[dict2Key]));
}
else
{
complexdicts.Add(dict2Key, new KeyValuePair<string, string>("Not Available", dict2[dict2Key]));
}
}
}
}
dict1 and dict2 are sample dictionaries and complexdicts object is what I want to export to excel.
Please let me know if I can do this in better way.
How about this?
Dictionary<string, string> dict1 = new Dictionary<string, string>();
Dictionary<string, string> dict2 = new Dictionary<string, string>();
Dictionary<string, KeyValuePair<string, string>> complexdicts = new Dictionary<string, KeyValuePair<string, string>>();
dict1.Add("A", "1");
dict1.Add("B", "2");
dict2.Add("A", "2");
dict2.Add("C", "3");
dict2.Add("D", "4");
var allKeys = dict1.Keys.Union(dict2.Keys);
foreach (var key in allKeys)
{
string val1;
if (!dict1.TryGetValue(key, out val1))
{
val1 = "Not Available";
}
string val2;
if (!dict2.TryGetValue(key, out val2))
{
val2 = "Not Available";
}
complexdicts.Add(key, new KeyValuePair<string, string>(val1, val2));
}
How about this?
Dictionary<string, string> dict1 = new Dictionary<string, string>();
Dictionary<string, string> dict2 = new Dictionary<string, string>();
dict1.Add("A", "1");
dict1.Add("B", "2");
dict2.Add("A", "2");
dict2.Add("C", "3");
dict2.Add("D", "4");
var allKeys = dict1.Keys.Union(dict2.Keys);
// case 1
List<Tuple<string, string, string>> unionValues = new List<Tuple<string, string, string>>();
foreach (var key in allKeys)
{
unionValues.Add(new Tuple<string, string, string>(key, dict1.ContainsKey(key) ? dict1[key] : "N/A" , dict2.ContainsKey(key) ? dict2[key] : "N/A"));
}
// case 2
var result = (from key in allKeys
select new Tuple<string, string, string>(key, dict1.ContainsKey(key) ? dict1[key] : "N/A", dict2.ContainsKey(key) ? dict2[key] : "N/A")).ToList();
I am looking to compare string[] splitted if it exists in List<KeyValuePair<string, string>> myList. IF it does not then I would add it to List<string> as a seperate list of email addresses.
using LINQ might be a good option, please help with implementaion.
looking to compare string[] splitted if it exists in List<KeyValuePair<string, string>> myList
public void SendEmails(String esmails)
{
//splitting email string
string[] splitted = esmails.Emails.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
List<KeyValuePair<string, string>> myList = new List<KeyValuePair<string, string>>();
foreach (var email in GetEmails)
{
for (int i = 0; i < splitted.Count(); i++)
{
if (email.EmailAddress.Equals(splitted[i].Replace(";","")))
myList.Add(new KeyValuePair<string, string>(email.IdentificationNo, email.EmailAddress));
}
}
}
Use implicitly typed variable (var) if possible
You can achieve this by using join
public void SendEmails(String esmails)
{
//splitting email string
var splitted =
esmails.Split(new []{System.Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Replace(";", ""));
var matchings =
from s in splitted
join email in GetEmails on email.EmailAddress equals s
select new KeyValuePair<string, string>(email.IdentificationNo, email.EmailAddress);
var myList = matchings.ToList();
}
public void SendEmails(String esmails)
{
List<String> split = esmails.Split(new String[] { System.Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Replace(";", "")).ToList();
Dictionary<Int32, String> dictionary = new Dictionary<Int32, String>();
foreach (Email email in GetEmails())
{
foreach (String address in split)
{
if (email.EmailAddress.Equals(address))
dictionary[email.IdentificationNo] = email.EmailAddress;
}
}