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);
}
}
Related
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
I have method to add elements to list
Here is code
public static List<InputDevice> GetAudioInputDevices()
{
var inputs = new List<InputDevice>();
var enumerator = new MMDeviceEnumerator();
var devicesAudio = enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
foreach (var device in devicesAudio)
{
inputs.Add(new InputDevice()
{
Name = device.FriendlyName,
Status = device.State.ToString(),
DeviceId = device.ID,
Identifier = device.FriendlyName.Replace(" ", "").ToUpper()
});
}
return inputs;
}
But sometimes I can have duplicates in Identifier
How I can return list without duplicates on return?
There's a few ways to accomplish this, you could just skip the Adding of the item if it's already in the list:
foreach (var device in devicesAudio)
{
string identifier = device.FriendlyName.Replace(" ", "").ToUpper();
if (inputs.Any(input => input.Identifier == identifier))
continue;
inputs.Add(new InputDevice()
{
Name = device.FriendlyName,
Status = device.State.ToString(),
DeviceId = device.ID,
Identifier = identifier
});
}
Or you could group the list by the identifier after the foreach, something like this:
inputs = inputs.GroupBy(i => i.Identifier)
.Select(i => new InputDevice()
{
Identifier = i.Key,
Status = i.First().Status,
DeviceId = i.First().DeviceId,
Name = i.First().Name
}).ToList();
It really depends on what you need to do with the duplicated ones.
Hope it helps!
To make it faster you can use HashSet (complexity of Contains for HashSet is o(1)) and ask on each loop whether there already is a specific identifier in inputs List.
public static List<InputDevice> GetAudioInputDevices()
{
var inputs = new List<InputDevice>();
var enumerator = new MMDeviceEnumerator();
var devicesAudio = enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
var usedIdentifiers = new HashSet<string>();
foreach (var device in devicesAudio)
{
var identifier = device.FriendlyName.Replace(" ", "").ToUpper();
if (usedIdentifiers.Contains(identifier))
continue;
inputs.Add(new InputDevice()
{
Name = device.FriendlyName,
Status = device.State.ToString(),
DeviceId = device.ID,
Identifier = identifier
});
usedIdentifiers.Add(identifier);
}
return inputs;
}
The best way, I thing is this
public static List<InputDevice> GetAudioInputDevices()
{
var inputs = new List<InputDevice>();
var enumerator = new MMDeviceEnumerator();
var devicesAudio = enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
inputs = devicesAudio.GroupBy(d => d.FriendlyName.Replace(" ", "").ToUpper()).Select(g => g.First())
.Select(d => new InputDevice()
{
Name = d.FriendlyName,
Status = d.State.ToString(),
DeviceId = d.ID,
Identifier = d.FriendlyName.Replace(" ", "").ToUpper()
}).ToList();
return inputs;
}
Check in website information about HashSet.
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 this code which grabs the specified text from a webpage:
static void Main(string[] args)
{
using (var client = new WebClient())
{
var pageContent = client.DownloadString("http://www.modern-railways.com");
var regexTitle = new Regex(#"<span class='articleTitle'>(.+?)</span>");
var regexDate = new Regex(#"class='summaryText' data-ajax='false'>(.+?)</a></p><div");
foreach (Match title in regexTitle.Matches(pageContent))
{
var articleTitle = title.Groups[1].Value;
Console.WriteLine(articleTitle);
}
foreach (Match date in regexDate.Matches(pageContent))
{
var articleDate = date.Groups[1].Value;
Console.WriteLine(articleDate);
}
Console.ReadLine();
}
}
As it is now it prints all the articleTitle first and then all the articleDate. How can I get out 1st line ArticleTitle, second line articleDate and so on?
You can use LINQ and Zip method:
var titles = regexTitles.Matches(pageContent).Cast<Match>();
var dates = regexDate.Matches(pageContent).Cast<Match>();
var source = titles.Zip(dates, (t, d) => new { Title = t, Date = d })
foreach (var item in source)
{
var articleTitle = item.Title.Groups[1].Value;
var articleDate = item.Date.Groups[1].Value;
Console.WriteLine(articleTitle);
Console.WriteLine(articleDate);
}
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++;
}
}