I have a collection of objects that bind to a System.Web.UI.WebControls.ListControl:
foreach (var answer in SomeCollection)
{
System.Web.UI.WebControls.ListItem listItem = new System.Web.UI.WebControls.ListItem();
listItem.Value = answer.ID.ToString();
listItem.Text = answer.AnswerText;
listControl.Items.Add(listItem);
}
I now want to add a prefix to each answer of "A", "B", "C", "D", etc. So the output would look like:
A. Answer 1
B. Answer 2
C. Answer 3
The most answers we have is 10 so there is no need to worry about running out of letters. What is the right way to do this?
I have tried the following and it works, however I feel there should be a better way:
char[] alphabet = new char[]{ 'A', 'B', 'C', 'D', 'E', 'F', 'G',..., 'Y', 'Z' };
for (int i = 0; i < SomeCollection.Count; i++)
{
var answer = SomeCollection[i]
System.Web.UI.WebControls.ListItem listItem = new System.Web.UI.WebControls.ListItem();
listItem.Value = answer.ID.ToString();
listItem.Text = alphabet[i] + "." + answer.AnswerText;
listControl.Items.Add(listItem);
}
I'm assuming the main concern is that big character array. The following should also work...
char letter = 'A';
for (int i = 0; i < SomeCollection.Count; i++)
{
var answer = SomeCollection[i]
System.Web.UI.WebControls.ListItem listItem = new System.Web.UI.WebControls.ListItem();
listItem.Value = answer.ID.ToString();
listItem.Text = letter + "." + answer.AnswerText;
listControl.Items.Add(listItem);
letter++;
}
Off the top of my head, it sounds like you could zip a generated Enum.Range of characters with your collection... something like this, perhaps:
var someCollection = new List<string> {"Item1", "Item2", "Item3"};
var prefixes = Enumerable.Range('a', 'z' - 'a' + 1).Select(x => (char)x);
...
var items = prefixes.Zip(someCollection, (a,b) => a + " " + b);
Doing this, you can just assign the items collection directly to your listControl.
I don't actually have a compiler at hand, but how about something along the lines of this?
var charcode = (int)'A';
var items = SomeCollection.Select((answer, index) => new ListItem{
Value = answer.ID,
Text = String.Format("{0}.{1}", (char)(charcode+index), answer.AnswerText)
});
Related
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);
I've been wrapping my head around this to find an "elegant" solution but I'm not quite satisfied with it.
Possible input strings:
foo () bar ()
() bar
foo
()()foo () bar
There can be "unlimited" brackets and optional, non-bracket text inbetween the brackets. The content of these empty brackets are supposed to filled with data taking from a List<string> in the order of the list entries. If there no entries or not sufficient entries the brackets are untouched.
Possible string replacements:
foo () bar () replaced with x, y will result in foo (x) bar (y)
foo () bar () replaced with x will result in foo (x) bar ()
foo () bar () replaced with x, y, z will result in foo (x) bar (y)
I hope you get the idea.
Solutions:
The solutions I had so far are fiddling around with indexes and a lot special logic to handle the different cases.
I wondered if there is a more elegant solution with, for example regex. Maybe I'm too close at the problem right now and there is a simple solution :-)
Here is an approach I'm not really happy about (readability / easy to understand):
var guiIdentifierIndex = 0;
var guiIdentifierList = new List<string>{"x", "y", "z", "x", "y"};
var sourcePathItem = "foo ()";
string targetString = "";
var splittedPath = sourcePathItem.Split(new string[] { BRACKETS }, StringSplitOptions.None);
for (int index = 0; index < splittedPath.Length; index++)
{
var subPath = splittedPath[index];
var guiIdentifier = string.Empty;
if (guiIdentifierIndex < guiIdentifierList.Count)
{
guiIdentifier = guiIdentifierList[guiIdentifierIndex];
guiIdentifierIndex++;
}
targetString += subPath;
if (index < splittedPath.Length - 1)
targetString += string.Format("({0})", guiIdentifier);
}
http://volatileread.com/utilitylibrary/snippetcompiler?id=22718
You can use regular expressions, e.g.
String source = "foo () bar ()";
var guiIdentifierList = new List<String> {
"x", "y", "z", "x", "y" };
int guiIdentifierIndex = 0;
// result == "foo (x) bar (y)"
String result = Regex.Replace(source, #"\(\)", (MatchEvaluator) (
(match) => "(" + (guiIdentifierIndex < guiIdentifierList.Count
? guiIdentifierList[guiIdentifierIndex++]
: "") + ")"
));
Split the replacement string (x,y,z) on commas, then loop through the resulting array replacing the first occurrence of () by the appropriate value.
This link shows you how to replace the first instance : Replace first occurrence of pattern in a string
How about this:
var template = "foo () bar ()";
var replacements = new[] {"x", "y", "z"};
var components = template.Split(new []{"()"}, StringSplitOptions.RemoveEmptyEntries);
var sb = new StringBuilder();
var replacementCount = replacements.Count();
for (int i = 0; i < components.Count(); i++)
{
var value = i >= replacementCount ? String.Empty : replacements[i];
sb.AppendFormat("{0}({1})", components[i], value);
}
var substitutedTemplate = sb.ToString();
I would do this way:
List<string> guiIdentifiers = new List<string>{"x", "y", "z", "x", "y"};
string input = "foo () () () () () ()";
string[] splitPath = Regex.Split(input, #"(\(\))");
for (int i = 0; i < splitPath.Length; i++)
{
if (splitPath[i] == "()" && guiIdentifiers.Count > 0)
{
splitPath[i] = string.Format("({0})", guiIdentifiers.First());
guiIdentifiers.Remove(guiIdentifiers.First());
}
}
string result = string.Join("", splitPath);
And note that split is an irregular verb that has the third form as split also, splitted is really weird and I do not recommend you to use.
var numbers = new List<string>(new[] { "1", "2", "3" });
string original = "() test ()()";
String[] tokens = original.Split(new [] {"()"}, StringSplitOptions.None);
if (tokens.Count() >= numbers.Count())
return original;
return string.Concat(tokens.Take(tokens.Count() - 1)
.Select((t, i) => t + "(" + numbers[i] + ")"));
You could try to construct the target string in one foor loop like this ("Copy and Substitute")
EDIT: Now with "lookahead" to not substitute if closing bracket is missing.
var guiIdentifierIndex = 0;
var guiIdentifierList = new List<string> { "x", "y", "z" };
var sourcePathItem = "foo () bar () func()";
string targetString = "";
int srcIndex = 0;
foreach(char c in sourcePathItem)
{
targetString += c;
char lookahead = srcIndex < sourcePathItem.Length - 1 ? sourcePathItem[++srcIndex] : ' ';
if (c == '(' && lookahead == ')'
&& guiIdentifierIndex < guiIdentifierList.Count)
{
targetString += guiIdentifierList[guiIdentifierIndex++];
}
}
Console.WriteLine("Target: " + targetString);
This substitutes foo () bar () with x, y to foo (x) bar (y).
Generally I think using a Stringbuilder for the target string would be better when sourcePathItem and guidIdentifierList is getting bigger. e.g. less resource usage
Greetings
Hi you could used Regex groups. https://msdn.microsoft.com/en-us/library/ewy2t5e0(v=vs.110).aspx
The code below matches on ( and create a regex group which you could the used to replace.
var sourcePathItem = "()()foo () bar";
var q = new Queue<string>(new string[]{ "x", "y", "z", "x", "y" });
var replaced = Regex.Replace(sourcePathItem, #"\(", m =>
(m.Groups[1].Value + "(" + q.Dequeue())
);
StringBuilder sb = new StringBuilder();
String[] parts = sourcePathItem.Split(new String[]{"()"}, StringSplitOptions.None);
for (Int32 i = 0; i < parts.Length; i++){
sb.Append(parts[i]);
if (i < guiIdentifierList.Count && i + 1 < parts.Length)
sb.Append("(" + guiIdentifierList[i] + ")");
}
var result = sb.ToString();
What I am looking for is a way to replicate PHP str_replace() function in C#.
In PHP code It would look like:
$string = 'This is my demo y string!';
$search_for = array("y","x","z");
$replace_with = array("1","2","3");
if( str_replace($search_for,$replace_with,$string) ) {
$changed = true;
};
Where the y is changed to 1, x changed to 2 etc., And if anything was changed then set the variable changed or do any other code.
How to do the same in C#?
Thank you.
You can chain your string replaces like so:
var result = myString.Replace("y", "1").Replace("x", "2").Replace("z", "3");
That should do what you are looking for. An alternative approach if you had arrays with the replacements would be:
var originalChar = new List<char> { '1', '2', '3' };
var replaceWith = new List<char> { 'x', 'y', 'z' };
originalChar.ForEach(x => myString = myString.Replace(x, replaceWith[originalChar.IndexOf(x)]));
This could probably be more efficient but you get the idea.
Checking for a change:
As noted in the comments, checking for a change is as simple as checking if the original and the modified string are no longer equal:
var changed = (result != myString);
You can do it using LINQ and a Dictionary
var mappings = new Dictionary<char,char> { {'y', '1' }, { 'x', '2'} , {'z','3'}};
var newChars = inputString
.Select(x =>
{
if (mappings.ContainsKey(x))
return mappings[x];
return x;
})
.ToArray();
var output = new string(newChars);
bool changed = !(output == inputString);
This is a straightforward port, although I think it would be better to use C# the "conventional" way.
string inputString = "This is my demoy y string!";
string[] searchFor = new string[] { "y", "x", "z" }; // or char[] if you prefer
string[] replaceWith = new string[] { "1", "2", "3" };
if (ArrayReplace(searchFor, replaceWith, ref inputString))
{
bool changed = true;
}
bool ArrayReplace(string[] searchFor, string[] replaceWith, ref string inputString)
{
string copy = inputString;
for (int i = 0; i < searchFor.Length && i < replaceWith.Length; i++)
{
inputString = inputString.Replace(searchFor[i], replaceWith[i]);
}
return copy != inputString;
}
I have a list which contains some strings like below:
List<String> l = new List<String>(){
"item1 1",
"item2 2",
"item3 3",
"item1 4",
"item1 5",
"item3 6"};
I would like to sum the items which are the same. Example:
l = {"item1 10", "item2 2", "item3 9"}
I've tried this:
List<String> result = new List<String>();
for (int i = 0; i < total.Count; i++)
{
for (int j = 0; j < i; j++)
{
int diferenta = 0;
if (total[i].Substring(0, total[i].IndexOf(" ")).Equals(total[j].Substring(0, total[j].IndexOf(" "))))
{
diferenta = int.Parse(ExtractNumber(total[i].Substring(total[i].IndexOf(" ")))) + int.Parse(ExtractNumber(total[j].Substring(total[j].IndexOf(" "))));
total[i] = total[i].Replace(ExtractNumber(total[i].Substring(total[i].IndexOf(" "))), diferenta.ToString());
result.Add(total[i]);
}
}
And to get the distinct elements:
List<String> final = result.Distinct().toList();
My way is not correct at all so i want to ask you for help.
You can split each element, group by the first component, then sum the the second components up:
var groupQuery = l.Select(x => x.Split(new[] { ' ' })).GroupBy(x => x[0]);
var sumQuery = groupQuery.Select(x => new { x.Key, Total = x.Select(elem => int.Parse(elem[1])).Sum() });
foreach (var total in sumQuery)
{
Console.WriteLine("{0}: {1}", total.Key, total.Total);
}
This code obviously omits a bunch of error checking (what happens if a string doesn't split, or doesn't have a second component that can be parsed?), but that can be added in without too much difficulty.
List<string> outputList =
inputList.GroupBy(s => s.Split(' ')[0])
.Select(g.Key + " " + g.Sum(s => int.Parse(s.Split(' ')[1])).ToString());
Hooray for LINQ! :)
Note: There is no error trapping, and I am assuming the data is always correct. I have not tested the code for performance or errors.
Without handling bad data(for instance not splitted by a white-space etc.).
int sumTotal = (from i in l
let parts = i.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
let id = parts[0]
let count = int.Parse(parts[1])
group count by id into Numbers
where Numbers.Count() != 1
select Numbers.Sum()).Sum();
Edit: Haven't seen that you want to count every item even if it has no duplicate. That's even easier, you just need to remove where CountGroup.Count() != 1 from the query :)
So the complete LINQ query including handling data in wrong format:
int number=0;
int sum = (from i in l
let parts = i.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
where parts.Length==2
let id = parts[0]
let isInt = int.TryParse(parts[1], out number)
where isInt
group number by id into Numbers
select Numbers.Sum()).Sum();
Iterate over the list. For each item, split on " ". Add the prefix (splits[0]) to a map of (String:Integer). If string exists in map, then retrieve its value first, then add current item value (split[1]), then add the sum back to map.
At the end your map will have sum for each string. Just iterate through the map items to output it.
We have a list containing names of countries. We need to find names of countries from list b/w two letters. Like names of all countries with name starting b/w A-G and so on. We create following linq query but its ugly.
var countryAG = from elements in countryList
where elements.StartsWith("A") ||
elements.StartsWith("B") ||
elements.StartsWith("C") ||
elements.StartsWith("D") ||
elements.StartsWith("E") ||
elements.StartsWith("F") ||
elements.StartsWith("G") ||
elements.StartsWith("H")
select elements;
where countryList is created in C#
List< string> countryList = new List< string>();
Any help or any other efficient way to accomplish above task?
var countryAG = from elements in countryList
where elements[0] >= 'A' && elements[0] <= 'H'
select elements;
Chars are just numbers really, thus you can compare them as such
I can't test it right now, but I would try
countryList.Where((s) => s[0] <= 'A' && s[0] >= 'G');
You could use a prefix list and then use the prefix list for comparison - this way you can easily use different prefix lists based on what range you are interested in:
List<string> prefixList = new List<string>() { "A", "B", "C", "D", "E", "F", "G" };
var countryAG = countryList.Where( x=> prefixList.Any( p => x.StartsWith(p)));
Try
char[] startingLetters = new char[] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};
var countryAG =
from elements in countryList
where elements.IndexOfAny(startingLetters, 0, 1) == 0
select elements;
See here for information on IndexOfAny.
Try use this code:
var start = "a";
var end = "g";
var regex = new Regex(string.Format("^[{0}-{1}]", start, end));
var result = list.Where(x => regex.Match(x.ToLowerInvariant()).Success);
'start' and 'end' are static as an example.
I have two extension functions:
public static IEnumerable<char> Range(char start, char end)
{
return Enumerable.Range((int)start, (int)end - (int)start + 1).Select(i => (char)i);
}
which creates a range of characters, and
public static bool In(this string source, IEnumerable<string> collection)
{
return collection.Contains(source);
}
which is just the inverse of Contains, mostly for readability.
Together I can do:
where elements[0].In(Range('a', 'f')))
List<string> mainList = new List<string>()
{
"A","B","DD","EE","F","G","EE","CC","DD","Q","R","CC"
};
List<string> searchList = new List<string>() { "DD", "EE", "CC" };
var finalList = mainList.Where(x => searchList.Any(p => p == x)).ToList();