I am having a problem with
C# Version: 8.0 (.NET Core 3.1)
I got this error
tests/Fixture.cs(11,62): error CS0122: 'Program.FindRoutes(string[][])' is inaccessible due to its protection level
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
string[][] routes = new string[][] {
new string[] { "USA", "BRA" },
new string[] { "JPN", "PHL" },
new string[] { "BRA", "UAE" },
new string[] { "UAE", "JPN" }
};
}
static string FindRoutes(string[][] routes)
{
Dictionary<string, List<string>> graph = new Dictionary<string, List<string>>();
Dictionary<string, int> indegree = new Dictionary<string, int>();
foreach (var route in routes)
{
if (!graph.ContainsKey(route[0]))
{
graph[route[0]] = new List<string>();
indegree[route[0]] = 0;
}
if (!graph.ContainsKey(route[1]))
{
graph[route[1]] = new List<string>();
indegree[route[1]] = 0;
}
graph[route[0]].Add(route[1]);
indegree[route[1]]++;
}
Queue<string> queue = new Queue<string>();
foreach (var node in indegree)
{
if (node.Value == 0)
{
queue.Enqueue(node.Key);
}
}
string result = "";
while (queue.Count > 0)
{
string node = queue.Dequeue();
result += node + ", ";
foreach (var neighbor in graph[node])
{
indegree[neighbor]--;
if (indegree[neighbor] == 0)
{
queue.Enqueue(neighbor);
}
}
}
return result.TrimEnd(new char[] { ',', ' ' });
}
}
Related
I want to get an object from a Dictionary<string, object> using a string expression as key.
For example taking the following data structure:
var data = new Dictionary<string, object>()
{
{ "Products", new object[]
{
new Dictionary<string, object>()
{
{ "Name", "Tin of biscuits" }
}
}
}
}
I want to return the product name with the expression: "Products[0].Name".
This is just an example, the data could be of any depth and the string expression could be something like "BookStore.Books[3].Author.ContactDetails.Address" for eg.
So far I have been experimenting with Recursive methods and have also tried string.Split('.') with Aggregate Linq method, but I am struggling and I think this is a perfect little puzzle for SO.
Assuming you'll always have the Dictionary<string, object> and object[] in your data structure, this approach should work:
private static object? GetSelectedValueOrDefault(this Dictionary<string, object> data, string selector)
{
string[] selectorSegments = selector.Split('.');
if (selectorSegments.Length == 0)
{
return null;
}
object? currentNode = data.GetValueOrDefault(selectorSegments[0]);
if (currentNode == null)
{
return null;
}
for (int index = 1; index < selectorSegments.Length; index++)
{
string segment = selectorSegments[index];
if (currentNode is not Dictionary<string, object> dictionary)
{
return null;
}
var selectorWithIndex = GetSelectorAndElementIndexOrDefault(segment);
if (selectorWithIndex is not null &&
currentNode is Dictionary<string, object> dict)
{
currentNode = dict.GetValueOrDefault(selectorWithIndex.Value.ItemSelector);
currentNode = GetElementOrDefault(currentNode, selectorWithIndex.Value.Index);
continue;
}
currentNode = dictionary.GetValueOrDefault(segment);
if (index == selectorSegments.Length - 1)
{
return currentNode;
}
}
return null;
}
private static object? GetElementOrDefault(object? currentNode, int index)
{
if (currentNode is not object[] array)
{
return null;
}
if (index >= array.Length)
{
return null;
}
return array[index];
}
private static (string ItemSelector, int Index)? GetSelectorAndElementIndexOrDefault(string segment)
{
if (!segment.Contains('['))
{
return null;
}
string[] result = segment.Split('[', ']');
return (result[0], int.Parse(result[1]));
}
Example
var data = new Dictionary<string, object>()
{
{
"BookStore",
new Dictionary<string, object>()
{
{
"Name",
"The Book Store"
},
{
"Books",
new object[]
{
new Dictionary<string, object>(),
new Dictionary<string, object>(),
new Dictionary<string, object>(),
new Dictionary<string, object>()
{
{
"Author",
new Dictionary<string, object>()
{
{
"Name",
"Luke T O'Brien"
},
{
"ContactDetails",
new Dictionary<string, object>()
{
{
"Address",
"Some address"
}
}
}
}
}
}
}
}
}
}
};
Console.WriteLine(data.GetSelectedValueOrDefault("BookStore.Name"));
Console.WriteLine(data.GetSelectedValueOrDefault("BookStore.Books[3].Author.Name"));
Console.WriteLine(data.GetSelectedValueOrDefault("BookStore.Books[3].Author.ContactDetails.Address"));
Output
The Book Store
Luke T O'Brien
Some address
I'm using csvHelper (version 2.8.4) to write a class to csv.
My class looks like this:
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict{ get; set; }
}
Is it possible to write a mapper that maps Dict property to multiple columns? using some sort of converter?
for example if the class has the values:
Amount = 15
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
I want the resulting csv to be:
Amount,a1,b1
15,a2,b2
Thanks!
Possibly the easiest way is going to be to manually write out the dictionary part.
*** Update to work with CsvHelper Version 2.8.4 ***
void Main()
{
var records = new List<classA>
{
new classA {
Amount = 15,
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
}
};
using (var csv = new CsvWriter(Console.Out))
{
var dict = records.First().Dict;
var properties = typeof(classA).GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.Name != "Dict")
{
csv.WriteField(property.Name);
}
}
foreach (var item in dict)
{
csv.WriteField(item.Key);
}
csv.NextRecord();
foreach (var record in records)
{
foreach (PropertyInfo property in properties)
{
if (property.Name != "Dict")
{
csv.WriteField(property.GetValue(record));
}
}
foreach (var item in record.Dict)
{
csv.WriteField(item.Value);
}
csv.NextRecord();
}
}
}
// You can define other methods, fields, classes and namespaces here
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict { get; set; }
}
*** Works for current Version 27.2.1 ***
void Main()
{
var records = new List<classA>
{
new classA { Amount = 15, Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"} },
};
using (var csv = new CsvWriter(Console.Out, CultureInfo.InvariantCulture))
{
var dict = records.First().Dict;
csv.WriteHeader<classA>();
foreach (var item in dict)
{
csv.WriteField(item.Key);
}
csv.NextRecord();
foreach (var record in records)
{
csv.WriteRecord(record);
foreach (var item in record.Dict)
{
csv.WriteField(item.Value);
}
csv.NextRecord();
}
}
}
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict { get; set; }
}
As mentioned in linked question, you may use ExpandoObject to serialize dictionary.
The following code will work for writing to CSV only, it's converting classA objects to ExpandoObject during serialization, including Amount property which is added manually.
public static List<dynamic> ToExpandoObjects(IReadOnlyList<classA> aObjects)
{
var allKeys = aObjects
.SelectMany(a => a.Dict.Keys)
.Distinct()
.ToHashSet();
var result = new List<dynamic>();
foreach (var a in aObjects)
{
var asExpando = new ExpandoObject();
var asDictionary = (IDictionary<string, object>)asExpando;
asDictionary[nameof(classA.Amount)] = a.Amount;
foreach (var key in allKeys)
{
if(a.Dict.TryGetValue(key, out var value))
asDictionary[key] = value;
else
asDictionary[key] = null;
}
result.Add(asExpando);
}
return result;
}
...
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(ToExpandoObjects(records));
}
E.g. called as:
var records = new[] {
new classA
{
Amount = 15,
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
},
new classA
{
Amount = 15,
Dict = new Dictionary<string,string>{["c1"] = "c2",["b1"] = "b2"}
}
};
StringBuilder sb = new StringBuilder();
using (var writer = new StringWriter(sb))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(ToExpandoObjects(records));
}
Console.WriteLine(sb.ToString());
produces
Amount
a1
b1
c1
15
a2
b2
15
b2
c2
I've seen lots of questions about this, but I haven't seen any about doing it recursively. I've created some extension methods that do a pretty good job of pretty printing at a depth of 1. It looks like this:
public static string PrettyToString<K, V>(this Dictionary<K, V> dictionary)
{
string result = "{";
foreach (var kvp in dictionary)
{
result += $"({kvp.Key}, {kvp.Value}) ";
}
result += "}";
return result;
}
public static string PrettyToString<T>(this List<T> list)
{
string result = "{";
foreach (var element in list)
{
result += $"{element}, ";
}
result += "}";
return result;
}
public static string PrettyToString<T>(this T [] list)
{
string result = "{";
foreach (var element in list)
{
result += $"{element}, ";
}
result += "}";
return result;
}
But, what if K, V, or T is another collection like a List or a Dictionary? I want to recursively pretty print, but I'm not sure how to do that. As a result, my output looks like this:
{(foo, System.Collections.Generic.Dictionary`2[System.String,System.Boolean])...
I want it to look like this instead:
{(foo, {(bar, true)})...
I'm looking for methods that print recursively regardless of the nested types:
var x = new List<Dictionary<string, string>>();
var y = new Dictionary<Dictionary<string, string>, string>>();
var z = new Dictionary<Dictionary<string, string>, List<string>>>();
...
x.PrettyToString();
y.PrettyToString();
z.PrettyToString();
Should all recursively print out the contents. How do I achieve that?
I changed the signature of your methods and made them non-generic.
The trick is to determine the type before converting.
Look at the sample code below. I hope it helps.
Please look at the Ext class at the bottom of the source code.
Try it online
using System;
using System.Collections;
using System.Collections.Generic;
namespace ConsoleApp8
{
class Program
{
static void Main(string[] args)
{
var Dic = new Dictionary<int, string> { { 1, "Ali" }, { 2, "B" } };
Console.WriteLine(Dic.PrettyToString());
var Dic1 = new Dictionary<string, float> { { "Ali", 12.5f }, { "B", 99.9f } };
Console.WriteLine(Dic1.PrettyToString());
var Dic2 = new Dictionary<List<int>, string>
{
{ new List<int> { 1, 2, 3 }, "A" },
{ new List<int> { 4, 5, 6 }, "B" }
};
Console.WriteLine(Dic2.PrettyToString());
var Dic3 = new Dictionary<Dictionary<string, string>, string>
{
{ new Dictionary<string, string> { { "a", "A" }, { "b", "B" } }, "Capital" },
{ new Dictionary<string, string> { { "1", "1" }, { "2", "4" }, { "4", "16" } }, "Power" }
};
Console.WriteLine(Dic3.PrettyToString());
var Dic4 = new Dictionary<Dictionary<string, string>, List<string>>
{
{ new Dictionary<string, string> { { "a", "A" }, { "b", "B" } }, new List<string> { "A", "B" } },
{ new Dictionary<string, string> { { "1", "1" }, { "2", "4" }, { "4", "16" } }, new List<string> { "1", "2", "4" } }
};
Console.WriteLine(Dic4.PrettyToString());
var L = new List<List<int>>
{
new List<int> { 1, 2, 3 },
new List<int> { 4, 5, 6 }
};
Console.WriteLine(L.PrettyToString());
Console.ReadKey();
}
}
static class Ext
{
public static string PrettyToString(this IDictionary dictionary)
{
string result = "{";
foreach (var Key in dictionary.Keys)
{
result += string.Format("({0}, {1}) ", PrettyToString(Key), PrettyToString(dictionary[Key]));
}
result += "}";
return result;
}
public static string PrettyToString(this IEnumerable list)
{
string result = "{";
foreach (var element in list)
{
result += string.Format("{0}, ", PrettyToString(element));
}
result += "}";
return result;
}
private static string PrettyToString(object O)
{
var S = O as string;
if (S != null) return S;
var D = O as IDictionary;
if (D != null) return D.PrettyToString();
var L = O as IEnumerable;
if (L != null) return L.PrettyToString();
return O.ToString();
}
}
}
I am parsing a webpage, the issue I am coming across is that ["www.abc.com/"] and ["www.def.com/"] = new List() is getting a "syntax error,',' expected." I made a class that set property for the HtmlTarget, public string Id { get; set; } public Action<HtmlElement> Action { get; set; }, anybody have any suggestions ?
public void Spider(string sURL, HtmlDocument doc, int choice)
{
var urlTargets = new Dictionary<string, List<HtmlTarget>>
{
["www.abc.com/"] = new List<HtmlTarget>()
{
new HtmlTarget
{
Id = "search",
Action = e => e.SetAttribute("value", m_sMfgPartNbr)
},
new HtmlTarget
{
Id = "submit",
Action = e => e.InvokeMember("Click")
}
},
["www.def.com/"] = new List<HtmlTarget>()
{
new HtmlTarget
{
Id = "part",
Action = e => e.SetAttribute("value", m_sMfgPartNbr)
},
new HtmlTarget
{
Id = "submit",
Action = e => e.InvokeMember("Click")
}
}
};
List<HtmlTargets> targets = null;
if (urlTargets.TryGetValue(url, out targets))
{
var inputs = doc.Body.GetElementsByTagName("input");
foreach (HtmlElement element in inputs)
{
var id = element.GetAttribute("id");
foreach(var target in targets)
{
if (target.Id == id)
target.Action(element);
}
}
}
}
The correct syntax prior to C# 6 would be
var urlTargets = new Dictionary<string, List<HtmlTarget>>
{
{ "www.eciaauthorized.com/search", new List<HtmlTarget>()
...
},
{ "www.findchips.com/search", new List<HtmlTarget>()
...
}
}
I am trying to Split a search string containing Id=23||Header=This is a header||Description=This is a description into two arrays which I can use in the following context c.item[i] = property[i]. I attempted the solution below, but it does not match on the types any help would be appreciated :)
string[] stringSeparators = new string[] {"||"};
string[] testvalues = selectedSavedSearch.SearchString.Split(stringSeparators, StringSplitOptions.None).Select(sValue => sValue.Trim()).ToArray();
string[] items = new string[testvalues.Count()] ;
string[] properties = new string[testvalues.Count()] ;
for (int i = 0; i < testvalues.Count(); i++)
{
string[] values;
values = testvalues[i].Split('=').Select(sValue => sValue.Trim()).ToArray();
if (values.Count() > 0)
{
items[i] = values[0];
}
if (values.Count() > 1)
{
properties[i] = values[1];
}
}
for (int i = 0; i < items.Count(); i++)
{
currentSearch = typeof(BugManagerQueryOptions).GetProperty(items[i].ToString()).GetValue(properties[i], null);
}
I think you're misusing the GetValue:
currentSearch = typeof(BugManagerQueryOptions).GetProperty(items[i].ToString()).GetValue(properties[i], null);
Here's one way to get the value of the property via reflection:
PropertyInfo property = typeof(BugManagerQueryOptions).GetProperty(items[i]);
// query is the instance of BugManagerQueryOptions that you're trying to get the value from
var value= property.GetValue(query, null);
You're passing the property value to property.GetValue which will likely throw an exception.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UnitTest
{
public class Program
{
public static void Main(string[] args)
{
BugManagerQueryOptions bmqo = new BugManagerQueryOptions
{
Id = 64,
Header = "This is a header, that has not been set by reflection (yet)",
Description = "This is a description that has not been set by reflection (yet)"
};
var pairs = "Id=23||Header=This is a header||Description=This is a description"
.Split(new string[] { "||" }, StringSplitOptions.RemoveEmptyEntries)
.Select(q => new KeyValuePair<string, string>(q.Split('=')[0], q.Split('=')[1]));
// TEST : Getting values from the BugManagerQueryOptions instance (bmqo)
foreach (KeyValuePair<string, string> pair in pairs)
{
Console.WriteLine(typeof(BugManagerQueryOptions).GetProperty(pair.Key).GetValue(bmqo, null));
}
// TEST : Setting values to the BugManagerQueryOptions instance (bmqo)
foreach (KeyValuePair<string, string> pair in pairs)
{
if (typeof(BugManagerQueryOptions).GetProperty(pair.Key).PropertyType == typeof(Int32))
{
typeof(BugManagerQueryOptions).GetProperty(pair.Key).SetValue(bmqo, Int32.Parse(pair.Value), null);
}
else
{
typeof(BugManagerQueryOptions).GetProperty(pair.Key).SetValue(bmqo, pair.Value, null);
}
}
// TEST: Getting values from the BugManagerQueryOptions instance (bmqo) AFTER being set by reflection
foreach (KeyValuePair<string, dynamic> pair in pairs)
{
Console.WriteLine(typeof(BugManagerQueryOptions).GetProperty(pair.Key).GetValue(bmqo, null));
}
Console.Read();
}
}
public class BugManagerQueryOptions
{
public Int32 Id { get; set; }
public String Header { get; set; }
public String Description { get; set; }
}
}