I'm trying to test a form by submitting a combination of all values to see if it breaks. These are ComboBoxes that I have stored in an ExtraField class
public class ExtraField
{
public String Name = ""; //name of form key
public Dictionary<String, String> Options = new Dictionary<String, String>(); //Format: OptionText, Value
}
I have generated a list of these fields
List<ExtraField> efList = new List<ExtraField>();
I was thinking all possible combinations of these fields could be added to a string list that I can parse (I was thinking name=opt|name=opt|name=opt). I've provided an example of what would work below (where ExtraField list Count==3):
List<ExtraField> efList = new List<ExtraField>();
ExtraField f1 = new ExtraField();
f1.Name = "name1";
f1.Options.Add("text", "option1");
f1.Options.Add("text2", "option2");
f1.Options.Add("text3", "option3");
efList.Add(f1);
ExtraField f2 = new ExtraField();
f2.Name = "name2";
f2.Options.Add("text", "option1");
f2.Options.Add("text2", "option2");
f2.Options.Add("text3", "option3");
f2.Options.Add("text4", "option4");
efList.Add(f2);
ExtraField f3 = new ExtraField();
f3.Name = "name3";
f3.Options.Add("text2", "option1");
f3.Options.Add("text3", "option2");
f3.Options.Add("text4", "option3");
f3.Options.Add("text5", "option4");
f3.Options.Add("text6", "option5");
efList.Add(f3);
Should produce
name1=option1|name2=option1|name3=option1
name1=option1|name2=option1|name3=option2
name1=option1|name2=option1|name3=option3
name1=option1|name2=option1|name3=option4
name1=option1|name2=option1|name3=option5
name1=option1|name2=option2|name3=option1
name1=option1|name2=option2|name3=option2
name1=option1|name2=option2|name3=option3
name1=option1|name2=option2|name3=option4
name1=option1|name2=option2|name3=option5
name1=option1|name2=option3|name3=option1
name1=option1|name2=option3|name3=option2
name1=option1|name2=option3|name3=option3
name1=option1|name2=option3|name3=option4
name1=option1|name2=option3|name3=option5
name1=option1|name2=option4|name3=option1
name1=option1|name2=option4|name3=option2
name1=option1|name2=option4|name3=option3
name1=option1|name2=option4|name3=option4
name1=option1|name2=option4|name3=option5
name1=option2|name2=option1|name3=option1
...etc
All ExtraFields in the list need to have a value and I need all permutations in one format or another. It's a big list with a lot of permutations otherwise I'd do it by hand.
Well I did it... But I'm not proud of it. I'm sure there is a better way of doing it recursively. Hopefully this helps someone.
public List<String> GetFormPermutations(List<ExtraField> inList)
{
List<String> retList = new List<String>();
int[] listIndexes = new int[inList.Count];
for (int i = 0; i < listIndexes.Length; i++)
listIndexes[i] = 0;
while (listIndexes[inList.Count-1] < inList.ElementAt(inList.Count-1).Options.Count)
{
String cString = "";
//after this loop is complete. a line is done.
for (int i = 0; i < inList.Count; i++) {
String key = inList.ElementAt(i).Name;
Dictionary<String, String> cOptions = inList.ElementAt(i).Options;
String value = cOptions.ElementAt(listIndexes[i]).Value;
cString += key + "=" + value;
if (i < inList.Count - 1)
cString += "|";
}
retList.Add(cString);
listIndexes[0]++;
for(int i = 0; i < inList.Count -1; i++)
{
if (listIndexes[i] >= inList.ElementAt(i).Options.Count)
{
listIndexes[i] = 0;
listIndexes[i + 1]++;
}
}
}
return retList;
}
UPDATED ANSWER
So I managed to do it recursively. I haven't done this since college :D
Here's the whole class:
https://gist.github.com/Rastamas/8070ae7e1471d2183451a17bcf061376
PREVIOUS ANSWER BELOW
This goes through your list and adds the strings to a StringBuilder in the format you showed
foreach (var item in efList)
{
foreach (var option in item.Options)
{
stringBuilder.Append(String.Format("{0}={1}|", item.Name, option.Value));
}
stringBuilder.Remove(stringBuilder.Length - 1, 1);
stringBuilder.AppendLine();
}
Then you can just use stringBuilder.ToString() to get the whole list.
Related
My first question on SO:
I created this public class, so that I can store three elements in a list:
public class myMultiElementList
{
public string Role {get;set;}
public string Country {get;set;}
public int Commonality {get;set;}
}
In my main class, I then created a new list using this process:
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
I've added data to EmployeeRolesCountry and have validated that has 472 lines. However, when I try to retrieve it as below, my ForEach loop only retrieves the final line added to the list, 472 times...
foreach (myMultiElementList tmpClass in EmployeeRolesCountry)
{
string d1Value = tmpClass.Role;
Console.WriteLine(d1Value);
string d2Value = tmpClass.Role;
Console.WriteLine(d2Value);
int d3Value = tmpClass.Commonality;
Console.WriteLine(d3Value);
}
This was the most promising of the potential solutions I found on here, so any pointers greatly appreciated.
EDIT: adding data to EmployeeRolesCountry
/*
Before this starts, data is taken in via a csvReader function and parsed
All of the process below is concerned with two fields in the csv
One is simply the Country. No processing necessary
The other is bio, and this itself needs to be parsed and cleansed several times to take roles out
To keep things making sense, I've taken much of the cleansing out
*/
private void File_upload_Click(object sender, EventArgs e)
{
int pos = 0;
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
int a = 0;
delimiter = ".";
string token;
foreach (var line in records.Take(100))
{
var fields = line.ToList();
string bio = fields[5];
string country = fields[4];
int role_count = Regex.Matches(bio, delimiter).Count;
a = bio.Length;
for (var i = 0; i < role_count; i++)
{
//here I take first role, by parsing on delimiter, then push back EmployeeRolesCountry with result
pos = bio.IndexOf('.');
if (pos != -1)
{
token = bio.Substring(0, pos);
string original_token = token;
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
a = original_token.Length;
bio = bio.Remove(0, a + 1);
}
}
}
}
EDIT:
When grouped by multiple properties, this is how we iterate through the grouped items:
var employeesGroupedByRolwAndCountry = EmployeeRolesCountry.GroupBy(x => new { x.Role, x.Country });
employeesGroupedByRolwAndCountry.ToList().ForEach
(
(countryAndRole) =>
{
Console.WriteLine("Group {0}/{1}", countryAndRole.Key.Country, countryAndRole.Key.Role);
countryAndRole.ToList().ForEach
(
(multiElement) => Console.WriteLine(" : {0}", multiElement.Commonality)
);
}
);
__ ORIGINAL POST __
You are instantiating rc1 only once (outside the loop) and add the same instance to the list.
Please make sure that you do
var rc1 = new myMultiElementList();
inside the loop where you are adding the elements, and not outside.
All references are the same in your case:
var obj = new myObj();
for(i = 0; i < 5; i++)
{
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
now the list has 5 elements, all pointing to the obj (the same instance, the same object in memory), and when you do
obj.Prop1 = "Prop" + 5
you update the same memory address, and all the pointers in the list points to the same instance so, you are not getting 472 copies of the LAST item, but getting the same instance 472 times.
The solution is simple. Create a new instance every time you add to your list:
for(i = 0; i < 5; i++)
{
var obj = new myObj();
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
Hope this helps.
The string I want to split is an array of strings.
the array contains strings like:
G1,Active
G2,Inactive
G3,Inactive
.
.
G24,Active
Now I want to store the G's in an array, and Active or Inactive in a different array. So far I have tried this which has successfully store all the G's part but I have lost the other part. I used Split fucntion but did not work so I have tried this.
int i = 0;
for(i = 0; i <= grids.Length; i++)
{
string temp = grids[i];
temp = temp.Replace(",", " ");
if (temp.Contains(' '))
{
int index = temp.IndexOf(' ');
grids[i] = temp.Substring(0, index);
}
//System.Console.WriteLine(temp);
}
Please help me how to achieve this goal. I am new to C#.
If I understand the problem correctly - we have an array of strings Eg:
arrayOfStrings[24] =
{
"G1,Active",
"G2,Inactive",
"G3,Active",
...
"G24,Active"
}
Now we want to split each item and store the g part in one array and the status into another.
Working with arrays the solution is to - traverse the arrayOfStrings.
Per each item in the arrayOfStrings we split it by ',' separator.
The Split operation will return another array of two elements the g part and the status - which will be stored respectively into distinct arrays (gArray and statusArray) for later retrieval. Those arrays will have a 1-to-1 relation.
Here is my implementation:
static string[] LoadArray()
{
return new string[]
{
"G1,Active",
"G2,Inactive",
"G3,Active",
"G4,Active",
"G5,Active",
"G6,Inactive",
"G7,Active",
"G8,Active",
"G9,Active",
"G10,Active",
"G11,Inactive",
"G12,Active",
"G13,Active",
"G14,Inactive",
"G15,Active",
"G16,Inactive",
"G17,Active",
"G18,Active",
"G19,Inactive",
"G20,Active",
"G21,Inactive",
"G22,Active",
"G23,Inactive",
"G24,Active"
};
}
static void Main(string[] args)
{
string[] myarrayOfStrings = LoadArray();
string[] gArray = new string[24];
string[] statusArray = new string[24];
int index = 0;
foreach (var item in myarrayOfStrings)
{
var arraySplit = item.Split(',');
gArray[index] = arraySplit[0];
statusArray[index] = arraySplit[1];
index++;
}
for (int i = 0; i < gArray.Length; i++)
{
Console.WriteLine("{0} has status : {1}", gArray[i] , statusArray[i]);
}
Console.ReadLine();
}
seems like you have a list of Gxx,Active my recomendation is first of all you split the string based on the space, which will give you the array previoulsy mentioned doing the next:
string text = "G1,Active G2,Inactive G3,Inactive G24,Active";
string[] splitedGItems = text.Split(" ");
So, now you have an array, and I strongly recommend you to use an object/Tuple/Dictionary depends of what suits you more in the entire scenario. for now i will use Dictionary as it seems to be key-value
Dictionary<string, string> GxListActiveInactive = new Dictionary<string, string>();
foreach(var singleGItems in splitedGItems)
{
string[] definition = singleGItems.Split(",");
GxListActiveInactive.Add(definition[0], definition[1]);
}
What im achiving in this code is create a collection which is key-value, now you have to search the G24 manually doing the next
string G24Value = GxListActiveInactive.FirstOrDefault(a => a.Key == "G24").Value;
just do it :
var splitedArray = YourStringArray.ToDictionary(x=>x.Split(',')[0],x=>x.Split(',')[1]);
var gArray = splitedArray.Keys;
var activeInactiveArray = splitedArray.Values;
I hope it will be useful
You can divide the string using Split; the first part should be the G's, while the second part will be "Active" or "Inactive".
int i;
string[] temp, activity = new string[grids.Length];
for(i = 0; i <= grids.Length; i++)
{
temp = grids[i].Split(',');
grids[i] = temp[0];
activity[i] = temp[1];
}
I have created a program which collects:
HWID
public IP Address
Date and time when program is launched
Program is designed to append those values, each in "Environment.NewLine" and result looks like this:
Next step was to separate those entries, so I can have them in 3 different listBoxes and here is the class code I used :
public DB_List(string fajl) //Fajl u Listu pretvaranje
{
newFajl = fajl;
}
public Tuple < List < string > , List < string > , List < string >> ListSeparator()
{
string[] FajlA = File.ReadAllLines(newFajl);
List < string > one = new List < string > ();
List < string > two = new List < string > ();
List < string > three = new List < string > ();
{
for (int i = 0; i < FajlA.Length; i += 3)
{
one.Add(FajlA[i]);
two.Add(FajlA[i + 1]);
three.Add(FajlA[i + 2]);
}
}
return Tuple.Create(one, two, three);
}
Code in main Form :
private void Form1_Load(object sender, EventArgs e)
{
string a = (#"data\blabl.txt");
DB_List liste = new DB_List(a);
var Lista = liste.ListSeparator();
listBox1.DataSource = Lista.Item1; // HWID
listBox2.DataSource = Lista.Item2; // cpuIP
listBox3.DataSource = Lista.Item3; // cpuTime
}
The result is this :
Final :
In the screenshot I've selected what I would like to be displayed.
Basically, I would like:
duplicates to be removed from ListBox1 and ListBox2 ( latest entry to be displayed )
In ListBox3 - only latest date to be displayed according to the index of listBox1.DataSource and listBox2.DataSource
You want your lists to show only changes, right?
then your data structure is wrong.
It has to be something like
public List<Tuple<string,string, string>> ListSeparator()
{
string[] FajlA = File.ReadAllLines(newFajl);
var results =new List<Tuple<string, string, string>>();
for (int i = 0; i < FajlA.Length; i += 3)
{
results.add(new Tuple<string, string, string>(FajlA[i], FajlA[i + 1], FajlA[i + 2]);
}
return results;
}
Then on your load you can get distinct data and use them like this:
string a = (#"data\blabl.txt");
DB_List liste = new DB_List(a);
var Lista = liste.ListSeparator().Distinct();
listBox1.DataSource = Lista.Select(l => l.item1).tolist ; // HWID
class ExtractLinks
{
WebClient contents = new WebClient();
string cont;
List<string> links = new List<string>();
List<string> FilteredLinks = new List<string>();
List<string> Respones = new List<string>();
List<List<string>> Threads = new List<List<string>>();
public void Links(string FileName)
{
HtmlDocument doc = new HtmlDocument();
doc.Load(FileName);
foreach (HtmlNode link in doc.DocumentNode.SelectNodes("//a[#href]"))
{
HtmlAttribute att = link.Attributes["href"];
if (att.Value.StartsWith("http://rotter.net/forum/scoops1"))
{
links.Add(att.Value);
}
}
for (int i = 0; i < links.Count; i++)
{
int f = links[i].IndexOf("#");
string test = links[i].Substring(0, f);
FilteredLinks.Add(test);
}
for (int i = 0; i < FilteredLinks.Count; i++)
{
contents.Encoding = System.Text.Encoding.GetEncoding(1255);
cont = contents.DownloadString(FilteredLinks[i]);
GetResponsers(cont);
}
}
private void GetResponsers(string contents)
{
int f = 0;
int startPos = 0;
while (true)
{
string firstTag = "<FONT CLASS='text16b'>";
string lastTag = "&n";
f = contents.IndexOf(firstTag, startPos);
if (f == -1)
{
break;
}
int g = contents.IndexOf(lastTag, f);
startPos = g + lastTag.Length;
string responser = contents.Substring(f + firstTag.Length, g - f - firstTag.Length);
foreach (List<string> subList in Threads)
{
}
}
}
}
I created this variable :
List<List<string>> Threads = new List<List<string>>();
The first thing I don't know yet how to do is how to create inside Threads number of Lists according to the FilteredLinks.Count inside the Links method.
Second thing is in the GetResponsers method I did:
foreach (List<string> subList in Threads)
{
}
But what I want is that first time it will add all the values from variable responser to the first List in Threads. Then when it's getting to the break; it stop then and then in the Links methods its calling GetResponsers(cont); again this time I want that all the values in responser to be added to the second List in Threads.
I know that each time it's getting to the break; it will get the next FilteredLink from FilteredLinks.
How do I create number of Lists in Threads according to the FilteredLinks.Count?
How do I make the code in GetResponsers to add the responser ?
You don't need to specify the count for the number of lists in Threads, since it is a list, you can simply keep adding lists to it. So the first part is correct where you are declaring it.
The second part --> Your calling method will change. Look below for the calling method.
The third part --> Change private void GetResponsers(string contents) to private void GetResponsers(List threadList, string contents). Look below for implementation change.
Also the loop will look like this then
//other code you have
List<List<string>> Threads = new List<List<string>>();
public void Links(string FileName)
{
// ...other code you have
for (int i = 0; i < FilteredLinks.Count; i++)
{
threads.Add(new List<string>);
contents.Encoding = System.Text.Encoding.GetEncoding(1255);
cont = contents.DownloadString(FilteredLinks[i]);
GetResponsers(threads[threads.Count - 1], cont);
}
}
private void GetResponsers(List<string> threadList, string contents)
{
int f = 0;
int startPos = 0;
while (true)
{
string firstTag = "<FONT CLASS='text16b'>";
string lastTag = "&n";
f = contents.IndexOf(firstTag, startPos);
if (f == -1)
{
break;
}
int g = contents.IndexOf(lastTag, f);
startPos = g + lastTag.Length;
string responser = contents.Substring(f + firstTag.Length, g - f - firstTag.Length);
threadList.Add(responser);
}
}
PS: Please excuse the formatting.
How do i make List of Lists ? And then add to each List values?
The following codesnippet demonstrates you, how to handle List<List<string>>.
List<List<string>> threads = new List<List<string>>();
List<string> list1 = new List<string>();
list1.Add("List1_1");
list1.Add("List1_2")
threads.Add(list1);
List<string> list2 = new List<string>();
list1.Add("List2_1");
list1.Add("List2_2")
list1.Add("List2_3")
threads.Add(list2);
How do i create number of Lists in Threads according to the
FilteredLinks.Count ?
for(int i = 0; i < FilteredLinks.Count; i++)
{
var newList = new List<string>();
newList.Add("item1"); //add whatever you wish, here.
newList.Add("item2");
Threads.Add(newList);
}
I'm afraid I can't help you with Question #2, since I don't understand what you try to achieve there exactly.
For my homework, I have to use a SortedList to count words in a List with SortedList taking each entry and sorting it in alphabetical order before inserting. When it comes to display the data to the user, the data displayed should be displayed with sorting according to value instead of key.
Below is my attempt at this but I am getting 3 errors and I don't know how to resolve it. I am not allowed to use LINQ for this.
List<string> words = new List<string>(); <--- Already populated
This is my code of this implementation and I get 3 errors:
SortedList<string, int> d = new SortedList<string, int>();
bool InsideOfList = false;
foreach (string word in words)
{
InsideOfList = false;
foreach (KeyValuePair<string, int> keyvalPair in d)
{
if (keyvalPair.Key == word)
{
keyvalPair.Value += 1;
InsideOfList = true;
}
}
if (InsideOfList == false)
{
d.Add(word,1);
}
}
//Now instead of sorting by key I want to sort by value instead
SortedList<int, string> tempSortList = new SortedList<int, string>();
foreach (KeyValuePair<string, int> keyvalPair in d)
{
//trying to swap the value of previous SortedList with the Key of the new SortedList
tempSortList.Add(keyvalPair.Value, keyvalPair.Key);
}
for (int i = 0; i < 20; i++)
{
Console.WriteLine("\t{0}:\t{1}", tempSortList.GetKey(i), tempSortList.GetByIndex(i));
}
Here are my errors:
Property or indexer 'System.Collections.Generic.KeyValuePair<string,int>.Value' cannot be assigned to -- it is read only
'System.Collections.Generic.SortedList<int,string>' does not contain a definition for 'GetKey'
'System.Collections.Generic.SortedList<int,string>' does not contain a definition for 'GetByIndex'
You are confusing two things here. One is SortedList() and other is SortedList().
GetKey and GetKeyList are not present in SortedList(). You can use this instead of GetKey
tempSortList.ElementAt(index); // This will return you a KeyValuePair.
And for the first error you cannot assign value keyvalPair.Value has only getter. So you cannot set its value by doing += 1.
This is not quite good. Needs some improvement but it will work.
for (int i = 0; i < d.Count; i++)
{
if (d.ElementAt(i).Key == word)
{
d.Values[i] += 1;
}
}
or
for (int i = 0; i < d.Count; i++)
{
if (d.ElementAt(i).Key == word)
{
var val = d.ElementAt(i).Value + 1;
d.RemoveAt(i);
d.Add(word, val);
}
}
Please modify this line and check if it works. it should.
Console.WriteLine("\t{0}:\t{1}", tempSortList.GetKey(i), tempSortList.GetByIndex(i));
to
var key = tempSortedList.Keys[i];
var value = tempSortedList.Values[i];
Console.WriteLine("\t{0}:\t{1}", key, value);