Loop through sections of a collection - c#

Here is a loop I'm working on to create a JSON object collection:
var sb = new StringBuilder();
var list = DataAccess.Read.EventsByID(id);
foreach (var spevent in list)
{
sb.AppendFormat("'{0}':'{2}',",spevent.StartTimeDt.ToString("MM-dd-yyyy"), spevent.Link, spevent.Title);
}
The flaw is, if I have multiple events with the same date, I only get the last one because
window.eventscollection = {
'07-23-2013' : 'Item One',
'07-23-2013' : 'Item Two',
}
has two items with the same object name, and won't take duplicates.
The correct output would be to merge all items with the same date into one item as follows:
window.eventscollection = {
'07-23-2013' : 'Item OneItem Two',
}
It seems I need some kind of while or recursive loop to see if the next item has the same date as the current item and change the output, but I can't seem to get it right.
Thoughts?

You could group the items from the same date as
var sb = new StringBuilder();
var items = DataAccess.Read.EventsByID(id).GroupBy(p=>StartTimeDt.ToString("MM-dd-yyyy"));
then iterate through the grouping:
foreach (var item in items)
{
StringBuilder sb2 = new StringBuilder();
foreach(var subitem in item)
sb2.Append(String.Format("{2}",subitem.Link,subitem.Title));
sb.AppendFormat("'{0}':'{1}',",item.Key, sb2.ToString());
}

You first need to GroupBy on your list:
var sb = new StringBuilder();
var list = DataAccess.Read.EventsByID(id).GroupBy(e => e.StartTimeDt.Date);
And then you can loop within the loop
foreach (var dt in list)
{
sb.AppendFormat("'{0}'",dt.Key.ToString("yyyy-MM-dd"))
foreach (var spevent in dt)
{
sb.AppendFormat("'{1}',",, spevent.Link, spevent.Title);
}
}

Related

SubItems of ListView are not displayed in winforms

I am creating a winforms application in visual studio 2017, I am populating a ListView using a
List<KeyValuePair<string, string>>
Examples of the data are:
List<KeyValuePair<ABC, 123>>
List<KeyValuePair<ABC, 456>>
List<KeyValuePair<ABC, 789>>
List<KeyValuePair<DEF, 123>>
List<KeyValuePair<DEF, 233>>
I try to diplay this in a ListView, where I would like to have sometihng like this:
ABC
123
456
789
DEF
123
233
Where the ABC and the DEF are selectable only. I try to write a code to do this, but unfortunately it only displays the ABC and DEF without the subitems.
The code I wrote is:
workOrderClusters = GetItac.FilterWorkOrderClusters();
// GetItac.FilterWorkOrderClusters() is a
List<KeyValuePair<string,string>>
string current; string previous,
foreach (var workOrderCluster in workOrderClusters)
{
current = workOrderCluster.Key;
if (current != previous)
{
var listViewItem = new ListViewItem(workOrderCluster.Key);
foreach (var cluster in workOrderClusters)
{
if (cluster.Key == current)
{
listViewItem.SubItems.Add(cluster.Value);
}
}
}
previous = current;
listView1.Items.Add(listViewItem);
My question is, is there anyway to make the ListView display as expected ?
ListView shows sub items if it's in Details view and it has some columns.
Let's say you have the following data:
var list = new List<KeyValuePair<string, int>>(){
new KeyValuePair<string, int>("ABC", 123),
new KeyValuePair<string, int>("ABC", 456),
new KeyValuePair<string, int>("ABC", 789),
new KeyValuePair<string, int>("DEF", 123),
new KeyValuePair<string, int>("DEF", 233),
};
To convert your data structure to ListView items you can first group data based on the key:
var data = list.GroupBy(x => x.Key).Select(x => new
{
Key = x.Key,
Values = x.Select(a => a.Value)
});
Then add items and sub items to the control:
foreach(var d in data)
{
var item = listView1.Items.Add(d.Key);
foreach (var v in d.Values)
item.SubItems.Add(v.ToString());
}
And then setup ListView to show them:
listView1.View = View.Details;
var count = data.Max(x => x.Values.Count());
for (int i = 0; i <= count; i++)
listView1.Columns.Add($"Column {i+1}");
Note
As also mentioned in the comments, probably TreeView is more suitable to show such data. In case you want to add that data to TreeView, after grouping data you can use the following code:
foreach (var d in data)
{
var node = treeView1.Nodes.Add(d.Key);
foreach (var v in d.Values)
node.Nodes.Add(v.ToString());
}

How do i add data to a specific column in datagridview?

I have i already made 3 lists of elements that i want to insert on my datagridview,
but the problem is when i try to insert data on my datagrid a receive something like this,
so to insert data i used the following code:
IList<string> ruas = new List<string>();
foreach (var element in Gdriver.FindElements(By.ClassName("search-title")))
{
//ruas.Add(element.Text);
table.Rows.Add(element.Text);
}
IList<string> codps = new List<string>();
foreach(var Codpelement in Gdriver.FindElements(By.ClassName("cp")))
{
table.Rows.Add("",Codpelement.Text);
}
IList<string> Distritos = new List<string>();
foreach (var Distritoelement in Gdriver.FindElements(By.ClassName("local")))
{
//Distritos.Add(Distritoelement.Text);
table.Rows.Add("","",Distritoelement.Text.Substring(Distritoelement.Text.LastIndexOf(',') + 1));
}
Could you kindly, tell me a better way to make the data appear from top to bottom?
Thanks.
The problem is that you enter a single value per row. You should have three rows in total, but you have 3 * numberofcolumns rows. Instead of your current approach I recommend the following:
IList<string> ruas = new List<string>();
foreach (var element in Gdriver.FindElements(By.ClassName("search-title")))
{
ruas.Add(element.Text);
}
IList<string> codps = new List<string>();
foreach(var Codpelement in Gdriver.FindElements(By.ClassName("cp")))
{
codps.Add(Codpelement.Text);
}
IList<string> Distritos = new List<string>();
foreach (var Distritoelement in Gdriver.FindElements(By.ClassName("local")))
{
Distritos.Add(Distritoelement.Text.Substring(Distritoelement.Text.LastIndexOf(',') + 1));
}
for (int i = 0; i < ruas.Count; i++) {
table.Rows.Add(ruas.ElementAt(i), codps.ElementAt(i), Distritos.ElementAt(i));
}

Entity Framework: How to insert data while looping through multiple lists

I am attempting to insert data from two List.
I am able to successfully insert from one List but adding the second list using a foreach loop does not work as expected.
How do I loop through each of these list so that I can insert their values?
Code:
private void InsertList()
{
var listA = new List<string>();
var listB = new List<string>();
//Populate both list by splitting items in listbox
foreach (ListItem item in ListBox1.Items)
{
var components = item.Value.Split('/');
listA.Add(components.First());
listB.Add(components.Last());
}
using (DataContext dataContext = new DataContext())
{
foreach (var itemA in listA)
{
foreach (var itemB in listB)
{
LIST_OBJECTS listObject = new LIST_OBJECTS
{
LIST_ITEM_A = itemA,
LIST_ITEM_B = itemB
};
dataContext.LIST_OBJECTS.Add(listObject);
}
}
dataContext.SaveChanges();
}
}
What about a for loop?
for (var i = 0; i < listA.Count; i++)
{
LIST_OBJECTS listObject = new LIST_OBJECTS
{
LIST_ITEM_A = listA[i],
LIST_ITEM_B = listB[i]
};
dataContext.LIST_OBJECTS.Add(listObject);
}
Since you know from the creation of the Lists that they'll have the same number of elements, this is fine.
You can do it with LINQ
LIST_OBJECTS listObject = listA.Join(listB,
a=>listA.Indexof(a),
b=>listB.Indexof(b),
(a,b)=> new LIST_OBJECTS()
{
LIST_ITEM_A =a,
LIST_ITEM_B =b
}).ToList();

How to add nodes in treeview from a list

I have following code where I require to create the node and sub node that is to bind with the list.
I am converting it to array then I am trying to add, but I fail to do this How should I do it? Following is my code:
foreach (var item in ProductCategory)
{
TreeNode tr = new TreeNode(item.CatName);
List<dataObject> lst = objFreecusatomization.GetAllCustomItems(CategoryType.Dressing, item.CategoryID);
TreeNode[] sumItemList =new TreeNode[lst.Count];
foreach (var subItem in lst)
{
sumItemList[sumItemList] = new TreeNode { Name = subItem.Name, Text = subItem.Name, Checked = subItem.Selected };
}
treeCustomItem.Nodes.Add(item.CatName, sumItemList);
}
And I also need to assign key value, name to the items being added. through LinQ or lambda-expression. What's the best way?
This will fail: sumItemList[sumItemList] = new TreeNode ... The index of an array cannot be the array itself.
Since you have no indexer (because of the foreach) I suggest you use a List, like this:
foreach (var item in ProductCategory)
{
TreeNode treeCustomItem = new TreeNode(item.CatName);
List<dataObject> lst = objFreecusatomization.GetAllCustomItems(CategoryType.Dressing, item.CategoryID);
List<TreeNode> sumItemList = new List<TreeNode>();
foreach (var subItem in lst)
{
sumItemList.Add(new TreeNode { ... });
}
treeCustomItem.Nodes.AddRange(sumItemList.ToArray());
}
But since you're already iterating over your fetched subitems, you can also add the subitems directly instead of using an array/list. Your inner foreach would become:
foreach (var subItem in lst)
{
treeCustomItem.Nodes.Add(new TreeNode { ... });
}

Merge and Update Two Lists in C#

I have two List<T> objects:
For example:
List 1:
ID, Value where Id is populated and value is blank and it contains say IDs from 1 to 10.
1,""
2,""
...
10,""
List 2:
ID, Value and other attributes all filled with values but this list is a subset of List 1 in terms of IDs. (e.g only 3 items)
2,67
4,90
5,98
What I want is a merged list 1, but with updated values. Does anyone have any good extension method which will do this or any elegent code to perform this operation. The final list should be:
ID, Value
1,""
2,67 //value from list 2
3,""
4,90
5,98
6,""
...
10,""
use linq: list1=list2.Union(list1);
I would probably use a dictionary rather than a list:
// sample data
var original = new Dictionary<int, int?>();
for (int i = 1; i <= 10; i++)
{
original.Add(i, null);
}
var updated = new Dictionary<int, int>();
updated.Add(2, 67);
updated.Add(4, 90);
updated.Add(5, 98);
updated.Add(11, 20); // add
// merge
foreach (var pair in updated)
{
original[pair.Key] = pair.Value;
}
// show results
foreach (var pair in original.OrderBy(x => x.Key))
{
Console.WriteLine(pair.Key + ": " + pair.Value);
}
If you are talking about properties of an object, it will be trickier, but still doable.
This is O(m*n) but should do the job for arbitrary lists
foreach (var record in List1)
{
var other = List2.FirstOrDefault(x => x.Key == record.Key);
if(other != null) record.Value = other.Value;
}
If the lists are guaranteed ordered, then it could be brought down to O(n) at the cost of more code. The algortihm would be
Current items start as head of each list
While items remain in both lists
If the current item of list1 has lower key than list2 advance to next in list1
else if the current item of list2 has lower key than list1 advance to next in list2
else copy value from current list2 item into list1 item and advance both lists.
If you have both lists sorted by ID, you can use a variation of the classical merge algorithm:
int pos = 0;
foreach (var e in list2) {
pos = list1.FindIndex(pos, x => x.Id==e.Id);
list1[pos].Value = e.Value;
}
Note that this also requires list2 to be a strict subset of list1 in terms of ID (i.e. list1 really contains all ids of list2)
Of course you can also wrap this in an extension method
public static void UpdateWith<T>(this List<T> list1, List<T> list2)
where T:SomeIdValueSupertype {
int pos = 0;
foreach (var e in list2) {
pos = list1.FindIndex(pos, x => x.Id==e.Id);
list1[pos].Value = e.Value;
}
}
private void btnSearch_Click(object sender, EventArgs e)
{
String searchBy = cmbSearchBy.Text.ToString();
String searchFor = txtSearchFor.Text.Trim();
var List3 = (from row in JobTitleDB.jobList
where (row.JID.ToString()+row.JobTitleName.ToString().ToLower()).Contains(searchFor.ToLower())
select row).ToList();
if (searchBy == "All")
{
dgJobTitles.DataSource = null;
//dgJobTitles.DataSource = List1;
//dgJobTitles.DataSource = List2;
//dgJobTitles.DataSource = List1.Concat(List2);
//dgJobTitles.DataSource = List1.Union(List2);
dgJobTitles.DataSource = List3;
//dgJobTitles.DataSource=List1.AddRange(List2);
}
}
Dictionary<int, string> List1 = new Dictionary<int, string>();
List1.Add(1,"");
List1.Add(2,"");
List1.Add(3,"");
List1.Add(4,"");
List1.Add(5,"");
List1.Add(6,"");
Dictionary<int, string> List2 = new Dictionary<int, string>();
List2.Add(2, "two");
List2.Add(4, "four");
List2.Add(6, "six");
var Result = List1.Select(x => new KeyValuePair<int, string>(x.Key, List2.ContainsKey(x.Key) ? List2[x.Key] : x.Value)).ToList();

Categories