Creating a new list by incrementing two separate lists - c#

I'm trying to create a new list from two separate lists like so:
List 1 (sCat) = MD0, MD1, MD3, MD4
List 2 (sLev) = 01, 02, 03, R
Output-->
MD0-01
MD0-02
MD0-03
MD0-R
MD1-01
MD1-02
MD1-03
MD1-R
MD3-01
MD3-02
MD3-03
MD3-R
etc...
I would like to know if there is a function that would produce the results above. Ultimately, I would like the user to provide List 2 and have that information added to List 1 and stored as a new list that I could call later.
enter code here
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
List<string> sCat = new List<string>();
// add Categories for the Sheets
sCat.Add("MD0");
sCat.Add("MD1");
sCat.Add("MD3");
List<string> sLev = new List<string>();
// add Levels for the Project
sLev.Add("01");
sLev.Add("02");
sLev.Add("03");
sLev.Add("R");
for (int i = 0; i < sCat.Count; i++)
{
// I am getting stuck here.
// I don't know how to take one item from the sCat list and
// add it to the sLev List incrementally.
Console.WriteLine(sCat[i],i);
}
Console.ReadLine();
}
}

Combine the values of all the elements selected from the first collection with the elements contained in the other collection:
var combined = sCat.SelectMany(s => sLev.Select(s1 => $"{s}-{s1}")).ToList();
Which is like iterating the two collections in a nested for/foreach loop, adding each combined element to a new List<string>:
List<string> combined = new List<string>();
foreach (var s1 in sCat)
foreach (var s2 in sLev) {
combined.Add(s1 + "-" + s2);
}

You can replace your for loop with following:
foreach(var sCatValue in sCat)
{
foreach(var sLevValue in sLev)
{
Console.WriteLine($"{sCatValue}-{sLevValue}");
}
}

private static void Main()
{
List<string> sCat = new List<string>();
// add Categories for the Sheets
sCat.Add("MD0");
sCat.Add("MD1");
sCat.Add("MD3");
List<string> sLev = new List<string>();
// add Levels for the Project
sLev.Add("01");
sLev.Add("02");
sLev.Add("03");
sLev.Add("R");
string dash = "-";
List<string> newList = new List<string>();
for (int i = 0; i < sCat.Count; i++)
{
for (int j = 0; j < sLev.Count; j++)
{
newList.Add(sCat[i] + dash + sLev[j]);
}
}
foreach (var item in newList)
{
Console.WriteLine(item);
}
Console.ReadLine();
}

Related

Trying to get all possible combinations from an unknown number of list of strings

Given a list of lists I am looking to create all possible combinations.
Example:
I have a list which holds 3 lists
List 1: Apple, Banana, Pear
List 2: Bed, Chair
List 3: Ben, Bob, Carl, Phil
From this I would expect to end up with a List of combinations
Apple_Bed_Ben
Apple_Bed_Bob
Apple_Bed_Carl
Apple_Bed_Phil
Apple_Chair_Ben
Apple_Chair_Bob
Apple_Chair_Carl
Apple_Chair_Phil
Banana_Bed_Ben
Banana_Bed_Bob
...
I don't know if I am missing something but I have been going in circles for hours now.
If I knew there would only ever be three lists I know I could just use nested for loops going through building the combination string but here there could be any number of lists.
Can anyone point me in the right direction to get this done?
This is what i currently have:
public class ChildrenNames
{
public string parentName;
public int numberOfNames;
public List<string> childrenNames = new List<string>();
}
public class Combination
{
public bool selected = true;
public string name;
}
List<Combination> GetAllCombinations()
{
List<Combination> allCombinations = new List<Combination>();
List<ChildrenNames> listOfChildren = new List<ChildrenNames>();
//Create list of children names for each parent object
for (int p = 0; p < parentObjects.Count; p++)
{
ChildrenNames cn = new ChildrenNames();
for (int c = 0; c < parentObjects[p].transform.childCount; c++)
cn.childrenNames.Add(parentObjects[p].transform.GetChild(c).name);
cn.parentName = parentObjects[p].name;
cn.numberOfNames = cn.childrenNames.Count;
listOfChildren.Add(cn);
}
for (int l = 0; l < listOfChildren.Count; l++)
{
for (int c = 0; c < listOfChildren[l].numberOfNames; c++)
{
if (l == 0)
{
for (int p = 0; p < listOfChildren.Count; p ++)
{
Combination combination = new Combination();
combination.name = listOfChildren[l].childrenNames[c];
allCombinations.Add(combination);
}
}
else
{
for (int i = 0; i < allCombinations.Count; i++)
allCombinations[i].name += "_" + listOfChildren[l].childrenNames[c];
}
}
}
return allCombinations;
}
This creates the correct number of combinations but for example throws out
Apple_Bed_Chair_Ben_Bob_Carl_Phil
I understand why this is happening but not how I can change this to get the expected result.
You need to keep track of the column for each of the lists in order for it to work properly.
public List<string> ZipStringLists(params List<string>[] lists)
{
var columnNo = new int[lists.Length];
var resultingList = new List<string>();
var stringBuilder = new StringBuilder();
while (columnNo[0] < lists[0].Count)
{
// Combine the items into one: Apple + Banana + Pear = AppleBananaPear
for (int i = 0; i < lists.Length; i++)
{
var listElement = lists[i];
// columnNo[i] contains which column to write out for the individual list
stringBuilder.Append(listElement[columnNo[i]]);
}
// Write out the result and add it to a result list for later retrieval
var result = stringBuilder.ToString();
resultingList.Add(result);
Console.WriteLine(result);
stringBuilder.Clear();
// We increment columnNo from the right to the left
// The next item after AppleBedBen is AppleBedBob
// Overflow to the next column happens when a column reaches its maximum value
for (int i = lists.Length - 1; i >= 0; i--)
{
if (++columnNo[i] == lists[i].Count
&& i != 0 /* The last column overflows when the computation finishes */)
{
// Begin with 0 again on overflow and continue to add to the next column
columnNo[i] = 0;
}
else
{
// No overflow -> stop
break;
}
}
}
return resultingList;
}
Usage:
List<string> list1 = new List<string> { "Apple", "Banana", "Pear" };
List<string> list2 = new List<string> { "Bed", "Chair" };
List<string> list3 = new List<string> { "Ben", "Bob", "Carl", "Phil" };
ZipStringLists(list1, list2, list3);
You could use a fairly generic solution that accepts any number of lists to incrementally build up the combinations. It's short, though not necessarily as optimal as other solutions as it builds intermediate lists:
public List<string> FindCombinations(params List<string>[] lists)
{
List<string> combinations = lists[0];
for (int i = 1; i < lists.Length; i++)
{
List<string> newCombinations = new List<string>(combinations.Count * lists[i].Count);
combinations.ForEach(s1 => lists[i].ForEach(s2 => newCombinations.Add($"{s1}_{s2}")));
combinations = newCombinations;
}
return combinations;
}
Usage:
List<string> combinations = FindCombinations(list1, list2, list3, list4, list5...)

How manipulate every string that a IList gives you?

I have a list that is given by this page http://www.codigo-postal.pt/?cp4=4710&cp3= , and as you can see if you visited the link there's a line that always end with the word "Braga", so with no further ado, what I want is to manipulate every string that the list gives me, into last word after the comma?
The List is given by this code:
IList<string> Distritos = new List<string>();
foreach (var Distritoelemen in Gdriver.FindElements(By.ClassName("local")))
{
//Distritos.Add(Distritoelement.Text);
table.Rows.Add(Distritoelement.Text);
}
In order to get the word after the last comma, run this code...
IList<string> Distritos = new List<string>();
foreach (var Distritoelemen in Gdriver.FindElements(By.ClassName("local")))
{
//Distritos.Add(Distritoelement.Text);
table.Rows.Add(Distritoelement.Text.Substring(Distritoelement.Text.LastIndexOf(',') + 1));
You might want to consider putting the Text into a local variable. If you don't want the extra space before the word, you can use .Trim() on the result of Substring as in ...LastIndexOf(',') + 1).Trim());
And if you have more then one list you should do
IList<string> Freguseia = new List<string>();
foreach (var freguesiaelement in Fdriver.FindElements(By.ClassName("local")))
{
Freguseia.Add(freguesiaelement.Text);
}
IList<string> GPS = new List<string>();
foreach (var gpselement in Fdriver.FindElements(By.ClassName("gps")))
{
GPS.Add(gpselement.Text);
}
for (int i = 0; i < Freguseia.Count; i++)
{
table.Rows.Add( Freguseia.ElementAt(i), GPS.ElementAt(i));
}

Generating values in a collection following a pattern in C#

I have following list of strings of tags:
List<string> Tags = new List<string> { "EmplId", "EmpName", "EmpAddress" };
I want to generate tags as following pattern:
EmplId1
EmpName1
EmpAddress1
EmplId2
EmpName2
EmpAddress2
EmplId3
EmpName3
EmpAddress3
I have written the following code:
List<string> Tags = new List<string> { "EmplId", "EmpName", "EmpAddress" };
foreach (var item in Tags)
{
for (int i = 1; i < 4; i++)
{
Console.WriteLine(item+i);
}
}
Console.ReadLine();
But this code generating an output as following:
EmplId1
EmplId2
EmplId3
EmpName1
EmpName2
EmpName3
EmpAddress1
EmpAddress2
EmpAddress3
How I can get the desired output ?
The inner loop really needs to be the outer loop. You want to iterate numbers then values
for (int i = 1; i < 4; i++)
{
foreach (var item in Tags)
{
Console.WriteLine(item+i);
}
}
You can generate items with Linq:
var items = from i in Enumerable.Range(1, 4)
from t in Tags
select t + i;
Produces following items:
EmplId1
EmpName1
EmpAddress1
EmplId2
EmpName2
EmpAddress2
EmplId3
EmpName3
EmpAddress3
EmplId4
EmpName4
EmpAddress4
Without Linq you should do as Jared pointed - swap loops.

My hashtable doesnt work

I am using a hashtable to read data from file and make clusters.
Say the data in file is:
umair,i,umair
sajid,mark,i , k , i
The output is like:
[{umair,umair},i]
[sajid,mark,i,i,k]
But my code does not work. Here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
namespace readstringfromfile
{
class Program
{
static void Main()
{
/* int i = 0;
foreach (string line in File.ReadAllLines("newfile.txt"))
{
string[] parts = line.Split(',');
foreach (string part in parts)
{
Console.WriteLine("{0}:{1}", i,part);
}
i++; // For demo only
}*/
Hashtable hashtable = new Hashtable();
using (StreamReader r = new StreamReader("newfile.txt"))
{
string line;
while ((line = r.ReadLine()) != null)
{
string[] records = line.Split(',');
foreach (string record in records)
{
if (hashtable[records] == null)
hashtable[records] = (int)0;
hashtable[records] = (int)hashtable[records] + 1;
Console.WriteLine(hashtable.Keys);
}
/////this portion is not working/////////////////////////////////////
foreach (DictionaryEntry entry in hashtable)
{
for (int i = 0; i < (int)hashtable[records]; i++)
{
Console.WriteLine(entry);
}
}
}
}
}
}
}
You're working with the records array when inserting into the hashtable (and when reading from it) instead of using the foreach-variable record. Also, in the final look, you iterate based on records instead of the current entry.Key. You're also declaring the hashtable in a too wide scope, causing all rows to be inserted into the same hashtable, instead of one per row.
public static void Main() {
var lines = new[] { "umair,i,umair", "sajid,mark,i,k,i" };
foreach (var line in lines) {
var hashtable = new Hashtable();
var records = line.Split(',');
foreach (var record in records) {
if (hashtable[record] == null)
hashtable[record] = 0;
hashtable[record] = (Int32)hashtable[record] + 1;
}
var str = "";
foreach (DictionaryEntry entry in hashtable) {
var count = (Int32)hashtable[entry.Key];
for (var i = 0; i < count; i++) {
str += entry.Key;
if (i < count - 1)
str += ",";
}
str += ",";
}
// Remove last comma.
str = str.TrimEnd(',');
Console.WriteLine(str);
}
Console.ReadLine();
}
However, you should consider using the generic Dictionary<TKey,TValue> class, and use a StringBuilder if you're building alot of strings.
public static void Main() {
var lines = new[] { "umair,i,umair", "sajid,mark,i,k,i" };
foreach (var line in lines) {
var dictionary = new Dictionary<String, Int32>();
var records = line.Split(',');
foreach (var record in records) {
if (!dictionary.ContainsKey(record))
dictionary.Add(record, 1);
else
dictionary[record]++;
}
var str = "";
foreach (var entry in dictionary) {
for (var i = 0; i < entry.Value; i++) {
str += entry.Key;
if (i < entry.Value - 1)
str += ",";
}
str += ",";
}
// Remove last comma.
str = str.TrimEnd(',');
Console.WriteLine(str);
}
Console.ReadLine();
}
You're attempting to group elements of a sequence. LINQ has a built-in operator for that; it's used as group ... by ... into ... or the equivalent method .GroupBy(...)
That means you can write your code (excluding File I/O etc.) as:
var lines = new[] { "umair,i,umair", "sajid,mark,i,k,i" };
foreach (var line in lines) {
var groupedRecords =
from record in line.Split(',')
group record by record into recordgroup
from record in recordgroup
select record;
Console.WriteLine(
string.Join(
",", groupedRecords
)
);
}
If you prefer shorter code, the loop be equivalently written as:
foreach (var line in lines)
Console.WriteLine(string.Join(",",
line.Split(',').GroupBy(rec=>rec).SelectMany(grp=>grp)));
both versions will output...
umair,umair,i
sajid,mark,i,i,k
Note that you really shouldn't be using a Hashtable - that's just a type-unsafe slow version of Dictionary for almost all purposes. Also, the output example you mention includes [] and {} characters - but you didn't specify how or whether they're supposed to be included, so I left those out.
A LINQ group is nothing more than a sequence of elements (here, identical strings) with a Key (here a string). Calling GroupBy thus transforms the sequence of records into a sequence of groups. However, you want to simply concatenate those groups. SelectMany is such a concatenation: from a sequence of items, it concatenates the "contents" of each item into one large sequence.

Create list<string> dynamically

I want to create a list in a button click event...every time the button is clicked a new list should be created having different name than the previous one...
Can anyone please help me out...I'm stuck on it...
Better create List<List<string>>
List<List<string>> lls = new List<List<string>>();
Button_Click()
{
List<string> str = new List<string>();
for (int i = 0; i < sub.Count; i++)
{
if (checkbx[i].Checked == true)
{
str.Add(checkbx[i].Text);
}
}
lls.Add(str);
}
hence their names would be lls[0], lls[1],... etc
List objects doesn't have names, variables have names.
Creating variables dynamically is mostly useless, especially in compiled languages. What you want is a collection where you can store multiple lists, e.g. a list of lists:
public List<List<string>> str = new List<List<string>>();
public void check() {
List<string> subs = new List<string>();
for (int i = 0; i < sub.Count; i++) {
if (checkbx[i].Checked) {
subs.Add(checkbx[i].Text);
}
}
str.Add(subs);
}
Use a dictionary of lists where the key is the list name and the value is the list itself.
//Defining Dictionary
Dictionary<string, List<string>> ListDict = new Dictionary<string, List<string>>();
//Add lists in Dictionary
OnClick(string listname)
{
ListDict.Add(listname, new List<string>());
}
//Add values in List
ListDict[listname].Add("xyz");

Categories

Resources