I'm trying to create a timetables.txt from other files, and I have this so far.
static void Main(string[] args)
{
string Routes = #"C:\Users\peepee poopoo\gtfs\routes.txt";
var column1 = new List<string>();
var column2 = new List<string>();
using (var rd = new StreamReader(Routes))
{
while (!rd.EndOfStream)
{
var splits = rd.ReadLine().Split(',');
column1.Add(splits[0]);
column2.Add(splits[1]);
}
}
// print column1
Console.WriteLine("Column 1:");
foreach (var element in column1)
Console.WriteLine(element);
// print column2
Console.WriteLine("Column 2:");
foreach (var element in column2)
Console.WriteLine(element);
}
However, I need the first column of every row in the list to have a number that just counts up from 1. How can I do this?
Just see the code written below and add it.
var dictionary = new Dictionart<string, string>();
using (var rd = new StreamReader(Routes))
{
while (!rd.EndOfStream)
{
var splits = rd.ReadLine().Split(',');
dictionary.Add(splits[0], splits[1]);
}
}
foreach(var item in dictionary)
{
Console.WriteLine(item.Key + "\t" + item.Value);
}
This was what worked:
string Routes = #"C:\Users\peepee poopoo\gtfs\routes.txt";
var dictionary = new Dictionary<string, string>();
using (var rd = new StreamReader(Routes))
{
while (!rd.EndOfStream)
{
var splits = rd.ReadLine().Split(',');
dictionary.Add(splits[0], splits[1]);
//dictionary.Add(splits[0], splits[1]);
}
}
foreach (var item in dictionary)
{
Console.WriteLine(item.Key + "\t" + item.Value);
}
The output then becomes
this
Related
I am new here and actually very new to c#.
In a nutshell, I am using c# via Visual Studio, I am calling a data from a database and I want to save these data in a .csv file. The problem now is that I want to save these data on two columns at the same time.
My code do write them in a file but shifted not on the right rows.
Dictionary<string, string> elementNames = new Dictionary<string, string>();
Dictionary<string, string> elementTypes = new Dictionary<string, string>();
var nodes = webservice.nepService.GetAllElementsOfElementType(webservice.ext, "Busbar", ref elementNames, ref elementTypes);
Dictionary<string, string> nodeResults = new Dictionary<string, string>();
Dictionary<string, string> nodeResults1 = new Dictionary<string, string>();
foreach (var nodename in elementNames.Values)
{
var nodeRes = webservice.nepService.GetResultElementByName(webservice.ext, nodename, "Busbar", -1, "LoadFlow", null);
var Uvolt = GetXMLAttribute(nodeRes, "U");
nodeResults.Add(nodename, Uvolt);
var Upercentage = GetXMLAttribute(nodeRes, "Up");
nodeResults1.Add(nodename, Upercentage);
StringBuilder strBldr = new StringBuilder();
string outputFile = #"C:\Users\12.csv";
string separator = ",";
foreach (var res in nodeResults)
{
strBldr.AppendLine($"{res.Key}{separator}{res.Value}");
}
foreach (var res1 in nodeResults1)
{
strBldr.AppendLine($"{separator}{separator}{res1.Value}");
}
File.WriteAllText(outputFile, strBldr.ToString());
}
this is the output of the previous code:
https://ibb.co/T4trQC3
I want these shifted values to move up beside the other values like that:
https://ibb.co/4S25v0h
Thank you
if you look to the code you are using AppendLine
strBldr.AppendLine($"{separator}{separator}{res1.Value}");
and if you want to append on same line just use Append
strBldr.Append($"{separator}{separator}{res1.Value}");
EDITED:
in linq you can use Zip function to zip to lists
// using System.Linq;
var results = Results.Zip(Results1, (firstList, secondList) => firstList.Key + "," + firstList.Value + "," + secondList.Value);
Edit Full example
public static IDictionary<string, string> Results { get; set; }
public static IDictionary<string, string> Results1 { get; set; }
private static void Main(string[] args)
{
StringBuilder strBldr = new StringBuilder();
string outputFile = #"D:\12.csv";
Results = new Dictionary<string, string>()
{
{"N1", "20"},
{"N2", "0.399992"},
{"N3", "0.369442"},
{"N4", "0.369976"}
};
Results1 = new Dictionary<string, string>()
{
{"N1", "100"},
{"N2", "99.9805"},
{"N3", "92.36053"},
{"N4", "92.49407"}
};
IEnumerable<string> results = Results.Zip(Results1,
(firstList, secondList) => firstList.Key + "," + firstList.Value + "," + secondList.Value);
foreach (string res1 in results)
{
strBldr.AppendLine(res1);
}
File.WriteAllText(outputFile, strBldr.ToString());
}
for faster code you can try this
HashSet<Tuple<string, string, string>> values = new HashSet<Tuple<string, string, string>>();
var nodes = webservice.nepService.GetAllElementsOfElementType(webservice.ext, "Busbar", ref elementNames, ref elementTypes);
foreach (var nodename in elementNames.Values)
{
var nodeRes = webservice.nepService.GetResultElementByName(webservice.ext, nodename, "Busbar", -1, "LoadFlow", null);
var Uvolt = GetXMLAttribute(nodeRes, "U");
var Upercentage = GetXMLAttribute(nodeRes, "Up");
values.Add(Tuple.Create(nodename, Uvolt, Upercentage));
}
var output = string.Join("\n", values.ToList().Select(tuple => $"{tuple.Item1},{tuple.Item2},{tuple.Item3}").ToList());
string outputFile = #"C:\Users\12.csv";
File.WriteAllText(outputFile, output);
if the rowCount for Results and Results1 are same and the keys are in the same order, try:
for (int i = 0; i < Results.Count; i++)
strBldr.AppendLine($"{Results[i].Key}{separator}{Results[i].Value}{separator}{Results1[i].Value}");
Or, if the rows are not in the same order, try:
foreach (var res in Results)
strBldr.AppendLine($"{res.Key}{separator}{res.Value}{separator}{Results1.Single(x => x.Key == res.Key).Value}");
I have a sparsely populated excel file I want to extract two columns into a dictionary in C#. I have tried the following. This fails when it reads the blank lines. Is there a cleaner way to achieve the same. I don't care about any other values here. Just a mapping of AR ID to AR Type would do.
public class Table
{
private Dictionary<string, string> _ARID_ARTypeValues = new Dictionary<string, string>();
private string _arId;
public Table(string arId)
{
_arId = arId;
}
public void AddValue(string key, string value)
{
_ARID_ARTypeValues.Add(key, value);
}
}
public static IDictionary ParseCsvFile(StreamReader reader)
{
Dictionary<string, Table> tables = new Dictionary<string, Table>();
// First line contains column names.
var columnNames = reader.ReadLine().Split(',');
for (int i = 1; i < columnNames.Length; ++i)
{
var columnName = columnNames[i];
var ntable = new Table(columnName);
if ((columnName == "AR ID") || (columnName == "AR Type"))
{
tables.Add(columnName, ntable);
}
}
var line = reader.ReadLine();
while (line != null)
{
var columns = line.Split(',');
for (int j = 1; j < columns.Length; ++j)
{
var table = tables[columnNames[j]];
table.AddValue(columns[0], columns[j]);
}
line = reader.ReadLine();
}
return tables;
}
I would just use a CSV library, like CsvHelper and read the csv file with that.
Dictionary<string, string> arIdToArTypeMapping = new Dictionary<string, string>();
using (var sr = File.OpenText("test.csv"))
{
var csvConfiguration = new CsvConfiguration
{
SkipEmptyRecords = true
};
using (var csvReader = new CsvReader(sr, csvConfiguration))
{
while (csvReader.Read())
{
string arId = csvReader.GetField("AR ID");
string arType = csvReader.GetField("AR Type");
if (!string.IsNullOrEmpty(arId) && !string.IsNullOrEmpty(arType))
{
arIdToArTypeMapping.Add(arId, arType);
}
}
}
}
You can use Cinchoo ETL - an open source library, to read the csv and convert them to dictionary as simple as with few lines of code shown below
using (var parser = new ChoCSVReader("Dict1.csv")
.WithField("AR_ID", 7)
.WithField("AR_TYPE", 8)
.WithFirstLineHeader(true)
.Configure(c => c.IgnoreEmptyLine = true)
)
{
var dict = parser.ToDictionary(item => item.AR_ID, item => item.AR_TYPE);
foreach (var kvp in dict)
Console.WriteLine(kvp.Key + " " + kvp.Value);
}
Hope this helps.
Disclaimer: I'm the author of this library.
I have a HttpContext context and I iterate through some of its Request properties to collect info. Currently I do it this way:
if (context.Request.Headers?.Keys != null)
{
var items = new StringBuilder();
foreach (var key in context.Request.Headers.Keys)
{
items.AppendLine(key + " = " + context.Request.Headers[key]);
}
result.Headers = items.ToString();
}
if (context.Request.Form?.Keys != null)
{
var items = new StringBuilder();
foreach (var key in context.Request.Form.Keys)
{
items.AppendLine(key + " = " + context.Request.Form[key]);
}
result.Form = items.ToString();
}
if (context.Request.Query?.Keys != null)
{
var items = new StringBuilder();
foreach (var key in context.Request.Query.Keys)
{
items.AppendLine(key + " = " + context.Request.Query[key]);
}
result.Query = items.ToString();
}
I want to convert this repetitive code to a generic method (if you can suggest any other ways, I would be fine with them, too). I tried writing a generic method:
private static string ParseKeys<T>(IDictionary<object, object> dict)
{
var sb = new StringBuilder();
foreach (var key in dict.Keys)
{
sb.AppendLine(key + " = " + dict[key]);
}
return sb.ToString();
}
and calling it like this:
result.Headers = ParseKeys<IHeaderDictionary>(context.Request.Headers);
result.Form = ParseKeys<IFormCollection>(context.Request.Form);
result.Query = ParseKeys<IQueryCollection>(context.Request.Query);
But I get such errors: cannot convert from 'Microsoft.AspNetCore.Http.IHeaderDictionary' to 'System.Collections.Generic.IDictionary<object, object>'
I tried various combinations but I still couldn't manage to avoid errors. Am I trying to do impossible here, or is there a simple to do what I want?
Those collections you mention (IHeaderDictionary, IFormCollection and IQueryCollection) all implement the same interface: IEnumerable<KeyValuePair<string, StringValues>> so here you don't need a generic method. Instead, you can do something like this:
private static string ParseKeys(IEnumerable<KeyValuePair<string, StringValues>> values)
{
var sb = new StringBuilder();
foreach (var value in values)
{
sb.AppendLine(value.Key + " = " + string.Join(", ", value.Value));
}
return sb.ToString();
}
And call it as you were previously:
result.Headers = ParseKeys(context.Request.Headers);
result.Form = ParseKeys(context.Request.Form);
result.Query = ParseKeys(context.Request.Query);
You are using a generic method, but you are not using the generic type parameter T. As far as the IHeaderDictionary and the IFormCollection, it is enough to accept an IEnumerable<KeyValuePair<string, string[]>>, since both interfaces inherit it:
private static string ParseKeys(IEnumerable<KeyValuePair<string, string[]>> dict)
{
var sb = new StringBuilder();
foreach (var keyValuePair in dict)
{
sb.AppendLine(keyValuePair.Key + " = " + String.Join(", ", keyValuePair.Value));
}
return sb.ToString();
}
As far as the IQueryCollection is concerned, it is an IEnumerable<KeyValuePair<string, StringValues>>. You can easily transform this to the required type with an iterator:
private static IEnumerable<KeyValuePair<string, string[]>> Transform(IEnumerable<KeyValuePair<string, StringValues>> source) {
foreach(var item in source) {
yield return new KeyValuePair<string, string[]>(item.Key, item.Value.ToArray());
}
}
Eventually, you can call the method like:
result.Headers = ParseKeys(context.Request.Headers);
result.Form = ParseKeys(context.Request.Form);
result.Query = ParseKeys(Transform(context.Request.Query));
I need a more efficient way of producing multiple files from my data group.
Im using a List<MyObject> type and my object has some public properties in which I need to group the data by.
I have heard of Linq and it sounds like something I could use. However Im not sure how to go about it.
I need to produce a text file for each STATE, so grouping all the MyObjects (people) by state, then running a foreach look on them to build the TEXT file.
void Main()
{
List<MyObject> lst = new List<MyObject>();
lst.Add(new MyObject{ name = "bill", state = "nsw", url = "microsoft.com"});
lst.Add(new MyObject{ name = "ted", state = "vic", url = "apple.com"});
lst.Add(new MyObject{ name = "jesse", state = "nsw", url = "google.com"});
lst.Add(new MyObject{ name = "james", state = "qld", url = "toshiba.com"});
string builder = "";
foreach (MyObject item in myObjects) {
builder += item.name + "\r\n";
builder += item.url + "\r\n" + "\r\n\r\n";
}
and out to the `StreamWriter` will be the filenames by state.
In total for the above data I need 3 files;
-nsw.txt
-vic.txt
-qld.txt
Something like this, perhaps?
var groups = lst.GroupBy(x => x.state);
foreach (var group in groups)
{
using (var f = new StreamWriter(group.Key + ".txt"))
{
foreach (var item in group)
{
f.WriteLine(item.name);
f.WriteLine(item.url);
}
}
}
You def. could use LINQ here.
lst.GroupBy(r=> r.state).ToList().ForEach(r=> {
//state= r.Key
//
foreach (var v in r)
{
}
});
The thing about linq. If you want to know how to do something in it. Think "how would I do this in SQL". The keywords are for the most part the same.
You can actually produce entire content with LINQ:
var entryFormat = "{1}{0}{2}{0}{0}{0}";
var groupsToPrint = lst
.GroupBy(p => p.state)
.Select(g => new
{
State = g.Key,
// produce file content on-the-fly from group entries
Content = string.Join("", g.Select(v => string.Format(entryFormat,
Environment.NewLine, v.name, v.url)))
});
var fileNameFormat = "{0}.txt";
foreach (var entry in groupsToPrint)
{
var fileName = string.Format(fileNameFormat, entry.State);
File.WriteAllText(fileName, entry.Content);
}
Something like...
string builderNsw = "";
foreach (MyObject item in lst.Where(o=>o.state == 'nsw')) {
builderNsw += item.name + "\r\n";
builderNsw += item.url + "\r\n" + "\r\n\r\n";
}
...but there are probably many ways to achieve this.
Same as Above - Iterating through groups by group, can get group name also
int itemCounter = 1;
IEnumerable<DataRow> sequence = Datatables.AsEnumerable();
var GroupedData = from d in sequence group d by d["panelName"]; // GroupedData is now of type IEnumerable<IGrouping<int, Document>>
foreach (var GroupList in GroupedData) // GroupList = "document group", of type IGrouping<int, Document>
{
bool chk = false;
foreach (var Item in GroupList)
{
if (chk == false) // means when header is not inserted
{
var groupName = "Panel Name : " + Item["panelName"].ToString();
chk = true;
}
var count = itemCounter.ToString();
var itemRef = Item["reference"].ToString();
itemCounter++;
}
}
I am trying to parse the following string and get the result.
string test = "SiteA:Pages:1,SiteB:Pages:4,SiteA:Documents:6"
I am trying to get the following result after the split.
string SiteA = "Pages:1,Documents:6"
string SiteB = "Pages:4"
Here is my code but it doesn't seem to be working. How can I get all related "SiteA" and "SiteB"?
List<string> listItem = new List<string>();
string[] keyPairs = test.Split(',');
string[] item;
foreach (string keyPair in keyPairs)
{
item = keyPair.Split(':');
listItem.Add(string.Format("{0}:{1}", item[0].Trim(), item[1].Trim()));
}
I would use a Lookup for this:
string test = "SiteA:Pages:1,SiteB:Pages:4,SiteA:Documents:6";
var listItemsBySite = test.Split(',')
.Select(x => x.Split(':'))
.ToLookup(x => x[0],
x => string.Format("{0}:{1}",
x[1].Trim(),
x[2].Trim()));
You can then use it like this:
foreach (string item in listItemsBySite["SiteA"])
{
Console.WriteLine(item);
}
Here's my solution... pretty elegant in LINQ, you can use anonymous objects, Tuples, KeyValuePair, or your own custom class. I'm just using an anonymous type.
string test = "SiteA:Pages:1,SiteB:Pages:4,SiteA:Documents:6";
var results = test
.Split(',')
.Select(item => item.Split(':'))
.ToLookup(s => s[0], s => new { Key = s[1], Value = s[2] });
// This code just for display purposes
foreach (var site in results)
{
Console.WriteLine("Site: " + site.Key);
foreach (var value in site)
{
Console.WriteLine("\tKey: " + value.Key + " Value: " + value.Value);
}
}
Here is my code:
string test = "SiteA:Pages:1,SiteB:Pages:4,SiteA:Documents:6";
string[] data = test.Split(',');
Dictionary<string, string> dic = new Dictionary<string, string>();
for(int i = 0; i < data.Length; i++) {
int index = data[i].IndexOf(':');
string key = data[i].Substring(0, index);
string value = data[i].Substring(index + 1);
if(!dic.ContainsKey(key))
dic.Add(key, value);
else
dic[key] = string.Format("{0}, {1}", new object[] { dic[key], value });
}
Here is how I would do it:
SortedList<string, StringBuilder> listOfLists = new SortedList<string, StringBuilder>();
string[] keyPairs = test.Split(',');
foreach (string keyPair in keyPairs)
{
string[] item = keyPair.Split(':');
if (item.Length >= 3)
{
string nextValue = string.Format("{0}:{1}", item[1].Trim(), item[2].Trim());
if (listOfLists.ContainsKey(item[0]))
listOfLists[item[0]].Append(nextValue);
else
{
StringBuilder sb = new StringBuilder();
sb.Append(nextValue);
listOfLists.Add(item[0], sb);
}
}
}
foreach (KeyValuePair<string, StringBuilder> nextCollated in listOfLists)
System.Console.WriteLine(nextCollated.Key + ":" + nextCollated.Value.ToString());
This is what I would do (tested).
(However, does assume that all items will be correctly formatted).
And of course, it's not really optimized.
static void Main(string[] args)
{
string test = "SiteA:Pages:1,SiteB:Pages:4,SiteA:Documents:6";
Dictionary<String, List<String>> strings = new Dictionary<string, List<string>>();
String[] items = test.Split(',');
foreach (String item in items)
{
List<String> itemParts = item.Split(':').ToList();
String firstPart = itemParts[0];
itemParts.RemoveAt(0);
String secondPart = String.Join(":", itemParts);
if (!strings.ContainsKey(firstPart))
strings[firstPart] = new List<string>();
strings[firstPart].Add(secondPart);
}
// This is how you would consume it
foreach (String key in strings.Keys)
{
List<String> keyItems = strings[key];
Console.Write(key + ": ");
foreach (String item in keyItems)
Console.Write(item + " ");
Console.WriteLine();
}
}
Here's a solution using LINQ:
string test = "SiteA:Pages:1,SiteB:Pages:4,SiteA:Documents:6";
var dict = test
.Split(',')
.GroupBy(s => s.Split(':')[0])
.ToDictionary(g => g.Key,
g => string.Join(",",
g.Select(i => string.Join(":", i.Split(':').Skip(1)))
.ToArray()));
using System;
using System.Linq;
using System.Text.RegularExpressions;
class MyClass
{
static void Main(string[] args)
{
string test = "SiteA:Pages:1,SiteB:Pages:4,SiteA:Documents:6";
var sites = test.Split(',')
.Select(p => p.Split(':'))
.Select(s => new { Site = s[0], Key = s[1], Value = s[2] })
.GroupBy(s => s.Site)
.ToDictionary(g => g.Key, g => g.ToDictionary(e => e.Key, e => e.Value));
foreach (var site in sites)
foreach (var key in site.Value.Keys)
Console.WriteLine("Site {0}, Key {1}, Value {2}", site.Key, key, site.Value[key]);
// in your preferred format:
var SiteA = string.Join(",", sites["SiteA"].Select(p => string.Format("{0}:{1}", p.Key, p.Value)));
var SiteB = string.Join(",", sites["SiteB"].Select(p => string.Format("{0}:{1}", p.Key, p.Value)));
Console.WriteLine(SiteA);
Console.WriteLine(SiteB);
}
}