Read Array of Arrays - c#

I have a block of C# that looks like this
public static string[,] FileTypesDict = new string[,] {
{"txt", "ReadFile"},
{"doc", "ReadMSOfficeWordFile"},
{"docx", "ReadMSOfficeWordFile"},
{"xls", "ReadMSOfficeExcelFile"},
{"xlsx", "ReadMSOfficeExcelFile"},
{"pdf", "ReadPDFFile"},
};
I would like to use this inside another function like this...
static void FindFiles() {
foreach (string type[] in FileTypesDict) {
// Find all files with extension
string[] files = Directory.GetFiles(FilePath, type[0]);
// To be used in another fun way, the longer description
string filetype = type[1]
}
}
That, of course, doesn't work... It seems to only work when I do this -->
static void FindFiles() {
foreach (string type in FileTypesDict) {
Console.WriteLine(type);
}
}
That will print each part of each array, like this -->
txt
ReadFile
doc
ReadMSOfficeWordFile
docx
ReadMSOfficeWordFile
xls
ReadMSOfficeExcelFile
xlsx
ReadMSOfficeExcelFile
pdf
ReadPDFFile
I'd basically like to look over the array of arrays and use each array inside of the loop...

You should be using a Dictionary for this, as it makes things much neater and readable.
You could do this:
Dictionary<string, string> fileTypes = new Dictionary<string, string>()
{
{"txt", "ReadFile"},
{"doc", "ReadMSOfficeWordFile"},
{"docx", "ReadMSOfficeWordFile"},
{"xls", "ReadMSOfficeExcelFile"},
{"xlsx", "ReadMSOfficeExcelFile"},
{"pdf", "ReadPDFFile"}
};
foreach (KeyValuePair<string, string> file in fileTypes)
{
Console.WriteLine(String.Format("{0} - {1}", file.Key, file.Value));
}
Or if you wanted to make the value a collection of string, you could do this:
Dictionary<string, List<string>> fileTypesWithList = new Dictionary<string, List<string>>()
{
{ "txt", new List<string>() { "Some", "Other", "Data" }}
};
foreach (KeyValuePair<string, List<string>> file in fileTypesWithList)
{
foreach (string s in file.Value)
{
Console.WriteLine(String.Format("{0} - {1}", file.Key, s));
}
}

The solution to your question is to define FileTypesDict as string[][]. Now I agree with the comments that the way you should do it is with a Dictionary.

see here: http://msdn.microsoft.com/en-us/library/2s05feca.aspx
static void FindFiles()
{
for (int i = 0; i < FileTypesDict.Length; i++)
{
var fileType = FileTypesDict[i, 0];
var action = FileTypesDict[i, 1];
string[] files = Directory.GetFiles(FilePath, fileType);
}
}

Related

All the nested dictionaries holds the same value?

I'm trying to build this datastructure with a nested dictionary:
["A",["A",123]],
["B",["B",123]],
["C",["C",123]],
And then loop over the data structure and print out the values.
The first problem is, that all the nested dictionaries are the same {"C",123}.
I think it's because it is the same object, but I don't know how to overcome that. Can I dynamically create new objects in the loop ?
The other problem i face is in the loop where I try to print out the Values.
The compiler says that it can't convert Dictionary to Dictionary.
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
public static void Main()
{
List<string> liste = new() { "A", "B", "C" };
Dictionary<string, Dictionary<string, int>> DictOfDicts = new();
Dictionary<string, int> DictOfData = new();
foreach (string i in liste)
{
DictOfData.Clear();
DictOfData.Add(i, 123);
DictOfDicts.Add(i, DictOfData);
}
foreach (Dictionary<string, int> i in DictOfDicts)
{
Console.WriteLine("Some result");
}
}
}
}
You declared DictOfData outside of the foreach loop. Then, all the operations inside the loop are done on the same object. So, you are clearing and filling the same dictionary object over and over again, on each loop iteration.
Just move you declaration of DictOfData to inside the loop, and you'll be good to go.
Bonus:
The whole operation you displayed in the questions can be done with just this:
liste.ToDictionary(x => x, x => new Dictionary<string, int>() { { x, 123 } })
var liste = new List<string>() { "A", "B", "C" };
var DictOfDicts = new Dictionary<string, Dictionary<string, int>>();
foreach (var i in liste)
{
// Create here a new DictOfData to add it to DicOfCicts.
var DictOfData = new Dictionary<string, int>();
DictOfData.Add(i, 123);
DictOfDicts.Add(i, DictOfData);
}
The structure of DicOfDicts is,
["A",["A",123]],
["B",["B",123]],
["C",["C",123]],
I've used a slightly older C# language specification for the answer, and made the type declarations more clear for you to understand.
List<string> list = new List<string>() { "A", "B", "C" };
Dictionary<string, Dictionary<string, int>> parent = new Dictionary<string, Dictionary<string, int>>();
foreach (string i in list)
{
Dictionary<string, int> child = new Dictionary<string, int>();
child.Add(i, 123);
parent.Add(i, child);
}
foreach (KeyValuePair<string, Dictionary<string, int>> parentPair in parent)
{
Dictionary<string, int> childDictionary = parentPair.Value;
foreach (var childPair in childDictionary)
{
Console.WriteLine(childPair.Value);
}
}
It's a very easy exercise to fix your code. Simply replace the DictOfData.Clear(); with the declaration of DictOfData itself. In other words, move the line Dictionary<string, int> DictOfData = new(); into the loop. That way you have a fresh instance of the nested dictionary rather than reusing the old one.
Try this code:
List<string> liste = new() { "A", "B", "C" };
Dictionary<string, Dictionary<string, int>> DictOfDicts = new();
foreach (string i in liste)
{
Dictionary<string, int> DictOfData = new();
DictOfData.Add(i, 123);
DictOfDicts.Add(i, DictOfData);
}
foreach (KeyValuePair<string, Dictionary<string, int>> i in DictOfDicts)
{
Console.WriteLine($"[{i.Key},{String.Join(",", i.Value.Select(x => $"[{x.Key},{x.Value}]"))}]");
}

Iterate over dictionary values list in C# to check for specific key

I would like to iterate over dictionary values which is a list of strings in C# to check for all keys
Dictionary<string, List<string>> csvList = new Dictionary<string, List<string>>();
I want to check each key(string) in csvList and check if it exists in any values(List)
foreach(var events in csvList)
{
foreach(var action in csvList.Values) // But I want to loop through all the lists in dictionary, not just the list of event key
{
}
}
This is kind of strange but let's try to work through it. We don't usually want to iterate the keys of a dictionary. The reason to use one is we want to get the values very quickly if we already know the key.
In the spirit of answering the question, to iterate over a Dictionary's keys you have to use the Keys property. Note that nothing about the order of this collection is guaranteed.
var d = new Dictionary<string, int>();
d.Add("one", 1);
d.Add("two", 2);
foreach (var k in d.Keys) {
Console.WriteLine(k);
}
But I think maybe you had a problem and chose a Dictionary as the solution, then came here when that didn't work. What if the Dictionary isn't the problem?
It sounds like you have several List<string> instances and you're interested in if a particular list contains a particular string. Or maybe you want to know, "Which lists contain which string?" We can answer that with a dictionary structured slightly differently. I'm going to use arrays instead of lists because it's easier to type.
using System;
using System.Collections.Generic;
public class Program
{
private static void AddWord(Dictionary<string, List<int>> d, string word, int index) {
if (!d.ContainsKey(word)) {
d.Add(word, new List<int>());
}
d[word].Add(index);
}
private static List<int> GetIndexesForWord(Dictionary<string, List<int>> d, string word) {
if (!d.ContainsKey(word)) {
return new List<int>();
} else {
return d[word];
}
}
public static void Main()
{
var stringsToFind = new[] { "one", "five", "seven" };
var listsToTest = new[] {
new[] { "two", "three", "four", "five" },
new[] { "one", "two", "seven" },
new[] { "one", "five", "seven" }
};
// Build a lookup that knows which words appear in which lists, even
// if we don't care about those words.
var keyToIndexes = new Dictionary<string, List<int>>();
for (var listIndex = 0; listIndex < listsToTest.GetLength(0); listIndex++) {
var listToTest = listsToTest[listIndex];
foreach (var word in listToTest) {
AddWord(keyToIndexes, word, listIndex);
}
}
// Report which lists have the target words.
foreach (var target in stringsToFind) {
Console.WriteLine("Lists with '{0}':", target);
var indices = GetIndexesForWord(keyToIndexes, target);
if (indices.Count == 0) {
Console.WriteLine(" <none>");
} else {
var message = string.Join(", ", indices);
Console.WriteLine(" {0}", message);
}
}
}
}
foreach(var events in csvList)
{
foreach(var action in csvList.Values)
{
if (action.Contains(events.Key)) //Just use this, there is no point to iterate the list as you can use contains method
}
}

Take count of repeating words in file

I have code to take count of repeating words in file
Here it is
static void Main()
{
StreamReader f = new StreamReader(#"d:\C#\text.txt");
string s = f.ReadToEnd();
char[] separators = { };//here is symbols
List<string> words = new List<string>(s.Split(separators));
Dictionary<string, int> map = new Dictionary<string, int>();
foreach (string w in words)
if (map.ContainsKey(w)) map[w]++; else map[w] = 1;
foreach (string w in map.Keys)
Console.WriteLine("{0}\t{l}", w.map[w]);
}
But in this row Console.WriteLine("{0}\t{l}", w.map[w]); I have this error.
Error CS1061 'string' does not contain a definition for 'map' and no extension method 'map' accepting a first argument of type 'string' could be found
How I can fix this error?
If I undertood what you wanted, this will help:
List<string> words = new List<string>() { "c#", "html", "web service", "c#", "c#" };
Dictionary<string, int> map = new Dictionary<string, int>();
foreach (string w in words)
{
if (map.ContainsKey(w))
{
map[w] = map[w]+1;
}
else
{
map[w] = 1;
}
}
//to iterate through Dictionary<string, int> use this instead
foreach (KeyValuePair<string, int> entry in map)
{
Console.WriteLine($"{entry.Key}\t{entry.Value}");
}

Trying to compare two lists c# - Should work?

I have a method that looks like this:
GetDrawing(Dictionary<string, List<string>> AllDrawings, Dictionary<string, bool> ImportData, string[] ItemsToCompare)
Firstly, the method creates a new List<string> with all the items from ImportData<string, bool> that have the value true and can be found in string[] ItemsToCompare
Secondly, I would like to compare the new List<string> with the List from AllDrawings<string, List<string>>. The method is in the end supposed to return a string with the key from AllDrawings<string>, List<String>> where the two lists match.
I have now spent a lot of hours trying to figure this out myself and also tried every answer I could find to similar questions here on Stackoverflow but with no luck.
Below is the full code for my method. As mentioned above I've tried a lot of different methods to compare the lists but the one following below is the latest try.
public static string GetDrawing(Dictionary<string, List<string>> AllDrawings, Dictionary<string, bool> ImportData, string[] ItemsToCompare)
{
string FinalDrawing = "";
try
{
List<string> AllCorrect = new List<string>();
foreach (var item in ImportData)
{
if (item.Value == true && ItemsToCompare.Contains(item.Key))
AllCorrect.Add(item.Key);
}
AllCorrect.Sort();
foreach (var DrawItem in AllDrawings)
{
DrawItem.Value.Sort();
var match = AllCorrect.SequenceEqual(DrawItem.Value);
if (match == true)
{
FinalDrawing = DrawItem.Key;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return FinalDrawing;
}
My problem is that the return value from var match = AllCorrect.SequenceEqual(DrawItem.Value); is false and therefore the FinalDrawing is never set.
All answers are very appreciated.
Thanks in advance!
Ok.. I already said that in comments, but just to make sure that you don't get yelled at too much for not-using-linq and such:
your program seems correct up to the point you told us.
Here's a simple test. I provided some stub data that cover all things that you seem to check:
only true things from importedata
only things that are listed in itemstocompare
input lists are not sorted
-> http://rextester.com/HAE73942
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
public class Program
{
// your original function, nothing changed
public static string GetDrawing(Dictionary<string, List<string>> AllDrawings, Dictionary<string, bool> ImportData, string[] ItemsToCompare)
{
string FinalDrawing = "";
try
{
List<string> AllCorrect = new List<string>();
foreach (var item in ImportData)
{
if (item.Value == true && ItemsToCompare.Contains(item.Key))
AllCorrect.Add(item.Key);
}
AllCorrect.Sort();
foreach (var DrawItem in AllDrawings)
{
DrawItem.Value.Sort();
var match = AllCorrect.SequenceEqual(DrawItem.Value);
if (match == true)
{
FinalDrawing = DrawItem.Key;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return FinalDrawing;
}
public static void Main(string[] args)
{
var allDrawings = new Dictionary<string, List<string>>();
allDrawings.Add("aaa", new List<string>{ "a03", "a01", "a02" }); // originally unsorted
allDrawings.Add("bbb", new List<string>{ "b03", "b01", "b02" }); // originally unsorted
allDrawings.Add("ccc", new List<string>{ "c03", "c01", "c02" }); // originally unsorted
var import = new Dictionary<string, bool>();
import.Add("b01", false); // falsey
import.Add("a05", true); // not in comparison
import.Add("a03", true);
import.Add("c01", false); // falsey
import.Add("a02", true);
import.Add("a04", true); // not in comparison
import.Add("a01", true);
var toCompare = new string[9];
toCompare[0]="a01"; toCompare[1]="a02"; toCompare[2]="a03";
toCompare[3]="b01"; toCompare[4]="b02"; toCompare[5]="b03";
toCompare[6]="c01"; toCompare[7]="c02"; toCompare[8]="c03";
var result = GetDrawing(allDrawings, import, toCompare);
Console.WriteLine("Result: " + result);
}
}
it works fine and prints aaa as it should.
This means that you had to have overlooked something in the input data. Maybe some strings are uppercase/lowercase? Maybe some strings have whitespaces inside and others not?
This code :
List<string> AllCorrect = new List<string>();
foreach (var item in ImportData)
{
if (item.Value == true && ItemsToCompare.Contains(item.Key))
AllCorrect.Add(item.Key);
}
AllCorrect.Sort();
Can be reduced to :
List<string> AllCorect = ImportData.Where(vp =>
ItemsToCompare.Contains(vp.Key) && vp.Value).Select(vp => vp.Key).OrderBy(vp => vp).ToList();
To solve the second problem you can do :
return AllDrawings.First(l => l.Value.OrderBy(l2 => l2).SequenceEqual(AllCorect)).Key;
P.S.
If First() always throws an exception then it suggests that problem lays in how this lists are filled with values and this is a different question.
Example :
public static string GetDrawing(Dictionary<string, List<string>> AllDrawings, Dictionary<string, bool> ImportData, string[] ItemsToCompare)
{
List<string> AllCorect = ImportData.Where(vp =>
ItemsToCompare.Contains(vp.Key) && vp.Value).Select(vp => vp.Key).OrderBy(vp => vp).ToList();
return AllDrawings.First(l => l.Value.OrderBy(l2 => l2).SequenceEqual(AllCorect)).Key;
}
static void Main(string[] args)
{
List<string> list1 = new List<string>() { "one", "two", "three" };
List<string> list2 = new List<string>() { "five", "six", "seven" };
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>()
{
{"first", list1}, {"second", list2}
};
string[] itemsToCompare = { "one", "two", "three" };
var dict2 = new Dictionary<string, bool>()
{
{"one", true},
{"two", true},
{"three", true}
};
var result = GetDrawing(dict, dict2, itemsToCompare);
Console.WriteLine(result);
}
Output : first
If the strings really match also for casing your code would be correct. I propose you inspect your string sequences - create an readable string and add appropriate break points. Also try to sort case-insensitive if that is what is missing here
AllCorrect.Sort(StringComparer.InvariantCultureIgnoreCase);
var AllCorrectInfo = string.Join(", ", AllCorrect.ToArray());
foreach (var DrawItem in AllDrawings)
{
DrawItem.Value.Sort();
var DrawItemInfo = string.Join(", ", DrawItem.Value.ToArray());
var match = AllCorrect.SequenceEqual(DrawItem.Value, StringComparer.InvariantCultureIgnoreCase);
if (match == true)
{
FinalDrawing = DrawItem.Key;
}
}

What data structure should I use to look up a string from an array of possible strings?

If I have the following abstract data structure:
"blue", ["sky", "water", "blueberry"]
"green", ["grass", "frog", "lime", "leaf"]
"red", ["blood", "apple", "ruby", "firetruck"]
"purple", ["plum", "petunia"]
If I want to retrieve a "key" by passing in one of the matching values in the array, what data structure best supports this operation? I'm looking for a combination of ease-of-use (e.g. clean code) and efficiency.
Since it was brought up: Keys and values are unique, and no two values will be repeated amongst any key (e.g. there is no duplication anywhere).
Here's the way I would do it, but I'm pretty sure it's not the best way, as you're supposed to use a Dictionary by accessing the value by the key, not the other way around.
public class ContainerClass
{
private static Dictionary<string, string[]> Data { get; set; }
static ContainerClass()
{
Data = new Dictionary<string, string[]>
{
{"blue", new string[] {"sky", "water", "blueberry"}},
{"green", new string[] {"grass", "frog", "lime", "leaf"}},
{"red", new string[] {"blood", "apple", "ruby", "firetruck"}},
{"purple", new string[] {"plum", "petunia"}}
};
}
public static string GetValue(string lookup)
{
foreach(var item in Data)
{
if (item.Value.Contains(lookup))
{
return item.Key;
}
}
return null;
}
}
Example usage:
ContainerClass.GetValue("lime"); // Should return 'green'
From just the information you've provided, it seems the easiest solution would be to reverse the dictionary like this:
static ContainerClass()
{
Data = new Dictionary<string, string>
{
{"sky", "blue"},
{"water", "blue"},
{"blueberry", "blue"},
{"grass", "green"},
...
{"blood", "red"},
...
{"plum", "purple"},
...
};
}
So that you can look up values like this:
public static string GetValue(string lookup)
{
string result;
Data.TryGetValue(lookup, out result);
return result;
}
Of course, you can generate this 'inverted' dictionary from a normal 'forward' dictionary pretty easily with a little Linq:
var keyValueDict = new Dictionary<string, string[]>
{
{"blue", new string[] {"sky", "water", "blueberry"}},
{"green", new string[] {"grass", "frog", "lime", "leaf"}},
{"red", new string[] {"blood", "apple", "ruby", "firetruck"}},
{"purple", new string[] {"plum", "petunia"}}
};
var valueKeyDict = keyValueDict
.SelectMany(x => x.Value, Tuple.Create)
.ToDictionary(t => t.Item2, t => t.Item1.Key);
This will produce a dictionary that's equivalent to the one specified above.

Categories