I am receiving a string reply from serial port and this reply contains 3 different value. Every value is separated with ';'.
For example;
10;155.4587;0.01
I need to separate these values and add to a Listview box.
I've found examples of Split(';') function but i think it is not possible to assign split values to different arrays.
Is there any way to perform this extraction with using/not using split() function?
Thanks in advance for any help.
Assuming an array of input strings...
string[] a1 = new string[] {
"10; 155.4587; 0.01",
"20; 255.4587; 0.02",
"30; 355.4587; 0.03",
};
List<string> r1 = new List<string>();
List<string> r2 = new List<string>();
List<string> r3 = new List<string>();
foreach (string t1 in a1)
{
string[] t2 = t1.Split(";");
r1.Add(t2[0]);
r2.Add(t2[1]);
r3.Add(t2[2]);
}
There's a wide variety of methods to doing this, you could use a Regex to delimit each item and use Lambda functions.
You could do something more basic like manipulating the below drawn-out example:
string s = "10;155.4587;0.01";
string[] a = new String[1];
string[] b = new String[1];
string[] c = new String[1];
string[] z = s.Split(';');
for(int i=0; i< z.Length; i++)
{
switch(i)
{
case 0:
a[0] = z[i];
break;
case 1:
b[0] = z[i];
break;
case 2:
c[0] = z[i];
break;
}
}
Console.WriteLine(a[0] + ' ' + b[0] + ' ' + c[0]);
The above illustrates how to manipulate elements but doesn't scale exactly well you may wish to pursue the anonymous route with the first comment using lambdas (see mukesh kudi's answer).
You can get this with help of linq...
string s = "10;155.4587;0.01";
var arrList = s.Split(';').Select(x => new string[] { x }).ToArray();
Here arrList contains three arrays. but i am not sure how this will help you. if you want to bind this result with ListView you have to traverse this collection and get each array value and bind to listview. you can do this with single array by traverse it's index's.
EDIT
To add just one list view item use:
var s = "10;155.4587;0.01";
var values = s.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
var listViewItem = new ListViewItem(values[0]);
listViewItem.SubItems.Add(values[1]);
listViewItem.SubItems.Add(values[2]);
listView1.Items.Add(listViewItem);
Assuming you have multiple strings to populate the listBox, try:
ListView listView1 = new ListView();
listView1.Bounds = new Rectangle(new Point(10, 10), new Size(300, 200));
listView1.View = View.Details;
listView1.GridLines = true;
listView1.Columns.Add("TD");
listView1.Columns.Add("AD");
listView1.Columns.Add("CT", -2);
var sValues = new string[] { "10;155.4587;0.01", "11;156.4587;0.02", "12;157.4587;0.03" };
var values = sValues.Select(x => x.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
.Select(x =>
{
var listViewItem = new ListViewItem(x[0]);
listViewItem.SubItems.Add(x[1]);
listViewItem.SubItems.Add(x[2]);
return listViewItem;
});
listView1.Items.AddRange(values.ToArray());
Thanks for all the help.
With the suggestion of #Captain Wibble, i successfully decoded my replies and add to Listview item.
Here is what i did for anyone in same trouble;
First i added my data packages "\r\n"
10;12.2345;0.01\r\n
I used;
serial.ReadLine()
Function to receive incoming data.
To decode and store the data into a listview object i use;
var s = text;
string[] a = new String[3];
//string[] b = new String[1];
//string[] c = new String[1];
string[] z = s.Split(';');
for (int i = 0; i < z.Length; i++)
{
switch (i)
{
case 0:
a[0] = z[i];
break;
case 1:
a[1] = z[i];
break;
case 2:
a[2] = z[i];
break;
}
}
itm = new ListViewItem(a);
listView5.Items.Add(itm);
Related
I have a string array with values
patrick
portland
vic
and I want to achieve the following:
for the first pass I want to have an array with * appended to the end of each entry:
patrick*
portland*
vic*
for second pass, I want to replace * with a ~:
patrick*
portland*
vic~
patrick*
portland~
vic*
patrick~
portland*
vic*
for third pass, I want to replace another * with ~:
patrick~
portland*
vic~
patrick~
portland~
vic*
patrick*
portland~
vic~
and so on until all the * are replaced by ~.
Is there a way do it without recursion?
Edit 1:
Need the following strings generated based on: patrick portland vic
patrick*portland*vic*
patrick*portland*vic~
patrick*portland~vic*
patrick~portland*vic*
patrick~portland*vic~
patrick~portland~vic*
patrick*portland~vic~
patrick~portland~vic~
I thought it would be easier to split the string into an array and then work on.
Edit 2:
Managed to solve this using cartesian product.
string[] stnameSplit = streetName.Split(' ');
string[] chars = { "*", "~" };
var cartesianProduct = from name in stnameSplit
from cha in chars
select new { name, cha };
List<string> vals = cartesianProduct.Select(p => p.name + p.cha).ToList();
List<List<string>> embeddedList = new List<List<string>>();
int ctr = 0;
List<string> l = new List<string>();
foreach (string s in vals)
{
l.Add(s);
if (ctr % 2 == 1)
{
embeddedList.Add(l);
l = new List<string>();
}
ctr++;
}
var result = embeddedList.ToArray().CartesianProduct();
The last line calls the method CartesianProduct as described by Eric Lippert.
Thanks everyone for the help and guiding me in the right direction.
Given the solution that you posted in your question I thought it seemed a bit verbose. I thought I'd try to shorten.
Here it is:
string streetName = "patrick portland vic";
string[] split = streetName.Split(' ');
string[] chars = { "*", "~" };
IEnumerable<IEnumerable<string>> choices = split.Select(n => chars.Select(c => $"{n}{c}"));
IEnumerable<IEnumerable<string>> result = choices.CartesianProduct();
I'm currently playing with TvDbSharper (https://github.com/HristoKolev/TvDbSharper) and i have a question about IEnumerable.
What i'm trying to do is get all the Id for a given series and then add the result in a listView.
This code gives me the first Id in the list:
const int SeriesId = 78804;
var tasks = new List<Task<TvDbResponse<BasicEpisode[]>>>();
var firstResponse = await client.Series.GetEpisodesAsync(SeriesId, 1);
for (int i = 2; i <= firstResponse.Links.Last; i++)
{
tasks.Add(client.Series.GetEpisodesAsync(SeriesId, i));
}
var results = await Task.WhenAll(tasks);
var episodes = firstResponse.Data.Concat(results.SelectMany(x => x.Data));
epsListview.View = View.Details;
epsListview.Columns.Add("Episode", 100);
string[] arr = new string[4];
ListViewItem itm;
arr[0] = episodes.First().Id.ToString();
itm = new ListViewItem(arr);
epsListview.Items.Add(itm);
but what i want is to make a new line in the epsListview for each id available.
I never used IEnumerable and i'm still very novice using c#, i've been stuck with this problem for over a week now. can anyone help me with this ?
Thanks!!
It looks like you're wanting to build an array of IDs from an IEnumerable of episodes, and add that array to a single ListViewItem. This should do that.
string[] arr = episodes.Select(episode => episode.Id.ToString()).ToArray()
ListViewItem itm = new ListViewItem(arr);
epsListview.Items.Add(itm);
Okay So I have this Hashset that contains 3 items and I want to apply some logic on it such that I am able to append some predefined 3 values for the each item present inside the hashset
for example,
HashSet<string> hs = new HashSet<string>(); //it could be string or some other class object
hs.add("Red");
hs.add("Yellow");
hs.add("Blue");
//Some predefined values for those strings that I want to append to them
string[] str = {Alpha, Beta, Gamma}
The output I desire is:
unique strings associating "RedAlpha", "YellowBeta", "bluegamma"
for example s1 = "RedAlpha", s2 = "YellowBeta", s3 = "bluegamma";
I then want to apply some different logic to each of them later but then I guess that is a different thing
My Tried code
int count = 1;
int index = 0;
string s = "";
foreach(string strr in hs)
{
string s + count = strr + str[index]; // I don't know how to make new unique string
count++;
index++;
}
My other Tried Code,
foreach(string strr in hs)
{
string s = strr + str[index];
s = s + ","
index++;
}
s.split(",");
When you want to merge 2 collection together and perform some operation on them, use the Zip method. See this answer for an explanation of Zip method.
Here is how to achieve what you need:
HashSet<string> hs = new HashSet<string>();
hs.Add("Red");
hs.Add("Yellow");
hs.Add("Blue");
string[] str = { "Alpha", "Beta", "Gamma" };
List<KeyValuePair<string, string>> kvps =
hs.Zip(str, (left, right) => new KeyValuePair<string, string>(left, right))
.ToList();
If you want a dictionary, it is straight forward as well:
Dictionary<string, string> kvps =
hs.Zip(str, (left, right) => new { left, right })
.ToDictionary(x => x.left, x.right);
Put them in a list:
int index = 0;
var list = new List<string>();
foreach(string strr in hs)
{
list.Add(strr + str[index]);
index++;
}
Console.WriteLine(list[0]); //RedAlpha
I am looking to find the differences between two Lists of string arrays using the index 0 of the array as the primary key.
List<string[]> original = new List<string[]>();
List<string[]> web = new List<string[]>();
//define arrays for List 'original'
string[] original_a1 = new string[3]{"a","2","3"};
string[] original_a2 = new string[3]{"x","2","3"};
string[] original_a3 = new string[3]{"c","2","3"};
//define arrays for List 'web'
string[] web_a1 = new string[3]{"a","2","3"};
string[] web_a2 = new string[3]{"b","2","3"};
string[] web_a3 = new string[3]{"c","2","3"};
//populate Lists
original.Add(original_a1);
original.Add(original_a2);
original.Add(original_a3);
web.Add(web_a1);
web.Add(web_a2);
web.Add(web_a3);
My goal is to find what is in List 'original' but NOT in 'web' by using index 0 as the primary key
This is what I tried.
List<string> differences = new List<string>(); //differences go in here
string tempDiff = ""; // I use this to try and avoid duplicate entries but its not working
for(int i = 0; i < original.Count; i++){
for(int j = 0; j< web.Count; j++){
if(!(original[i][0].Equals(web[j][0]))){
tempDiff = original[i][0];
}
}
differences.Add(tempDiff);
}
OUTPUT:
foreach(string x in differences){
Console.WriteLine("SIZE " + differences.Count);
Console.WriteLine(x);
ConSole.ReadLine();
}
SIZE 3
SIZE 3
x
SIZE 3
x
Why is it reporting the mismatch 3 times instead of once?
Using linq you can just go:
var differences = orignal.Except(web).ToList();
Reference here
This will give you the values that are in original, that don't exist in web
Sorry didn't read your question properly, to answer your question:
You have a nested for-loop. So for each value of original (3) it will loop through all values of web (3), which is 9 loops total.
In 3 cases it doesn't match and therefore outputs 3 times.
I think this is what you want. I use Linq to grab the primary keys, and then I use Except to do original - web. By the way, you can use == instead of Equals with strings in C# because C# does a value comparison as opposed to a reference comparison.
List<string[]> original = new List<string[]>
{
new string[3] { "a", "2", "3" },
new string[3] { "x", "2", "3" },
new string[3] { "c", "2", "3" }
};
List<string[]> web = new List<string[]>
{
new string[3] { "a", "2", "3" },
new string[3] { "b", "2", "3" },
new string[3] { "c", "2", "3" }
};
var originalPrimaryKeys = original.Select(o => o[0]);
var webPrimaryKeys = web.Select(o => o[0]);
List<string> differences = originalPrimaryKeys.Except(webPrimaryKeys).ToList();
Console.WriteLine("The number of differences is {0}", differences.Count);
foreach (string diff in differences)
{
Console.WriteLine(diff);
}
And here it is without Linq:
var differences = new List<string>();
for (int i = 0; i < original.Count; i++)
{
bool found = false;
for (int j = 0; j < web.Count; j++)
{
if (original[i][0] == web[j][0])
{
found = true;
}
}
if (!found)
{
differences.Add(original[i][0]);
}
}
To answer your question: It is a nested for loop as stated in JanR's answer. This approach will make you reiterate to your web count 9 times, thus listing your mismatched key three times.
What could be a better way to do is this:
//Check for originals not introduced in web.
if(original.Count > web.Count)
{
for(int y = web.Count; y < original.Count; y++)
{
differences.Add(original[y][0]);
}
}
//Check if Web has value, if not, everything else is done on the first for loop
if(web.Count > 0)
{
for(int i = 0; i < original.Count; i++)
{
if(!original[i][0].Equals(web[i][0]))
differences.Add(original[i][0]);
}
}
Also, the output is in a for loop, when you just need one result, the length of the mismatch. You can do that without a loop.
Console.WriteLine("SIZE " + differences.Count);
This is, of course to make it kinda simpler if you're not used to using LINQ statements, but if you can do so with LINQ, then by all means, use LINQ as it's more efficient.
You can get the difference by using Except extension method like this:
var originalDic = original.ToDictionary(arr => arr.First());
var webDic = web.ToDictionary(arr => arr.First());
var differences =
originalDic
.Except(webDic, kvp => kvp.Key)
.Select(kvp => kvp.Value)
.ToList();
The trick here is to first convert your original and web lists into a Dictionary using the first element of each array as key and then perform Except.
With the help of Google and a bit of luck, I was able to write code which adds a string array to a list box and displays the duplicate total in a text box using LINQ. I now need to be able to read from the array and only display non-duplicate items in a second listbox.
Here's the code that I have so far:
private void Form1_Load(object sender, EventArgs e)
{
string[] MyStringArray = new string[20];
MyStringArray[0] = "Apple";
MyStringArray[1] = "Green";
MyStringArray[2] = "Apple";
MyStringArray[3] = "Red";
MyStringArray[4] = "Orange";
MyStringArray[5] = "Orange";
MyStringArray[6] = "Bananas";
MyStringArray[7] = "Yellow";
MyStringArray[8] = "Mango";
MyStringArray[9] = "Yellow";
MyStringArray[10] = "Cherry";
MyStringArray[11] = "Red";
MyStringArray[12] = "Fig";
MyStringArray[13] = "Brown";
MyStringArray[14] = "Fig";
MyStringArray[15] = "Brown";
MyStringArray[16] = "Fig";
MyStringArray[17] = "Orange";
MyStringArray[18] = "Brown";
MyStringArray[19] = "Cranberry";
lstbDup.Items.AddRange(MyStringArray);
List<string> dups = new List<string>();
for (int i = 0; i < MyStringArray.Length; i++)
{
string current = MyStringArray[i];
if (MyStringArray.Count(s => s == current) > 1 &&
!dups.Contains(current))
{
dups.Add(current);
}
}
txtdupdisp.Text += dups.Count.ToString();
}
Use LINQ's .Distinct() operator to remove duplicate items from a sequence:
var uniques = MyStringArray.Distinct().ToList();
foreach(string s in uniques)
yourSecondListBox.Items.Add(s);
Or simply
yourSecondListBox.Items.AddRange(MyStringArray.Distinct().ToArray());
However as stated by another answer, your question is not clear. The code above retrieves every string that appears at least one time in your array. This means that also the word 'Apple' (it appears 2 times) will be included in the second listbox.
Instead, if you want only the items that appears just one time then the answer from vc 74 is the correct one albeit a more compact version exists:
List<string> nonDuplicates = MyStringArray.GroupBy(x => x)
.Where(group => group.Count()==1)
.SelectMany(group => group).ToList();
Linq is really funny and it seems that it gives infinite ways to skin the cat.
To retrieve the non duplicates:
var groups = MyStringArray.ToLookup(str => str);
List<string> nonDuplicates = groups.Where(group => (group.Count() == 1)).
Select(group => group.Key).ToList();
you can do it like this.
List<string> list = MyStringArray.Cast<string>().Distinct().ToList();
Once you get the filtered data bind this list to your control.
listBox1.DataSource = list;