Foreach in Foreach iterate at the same - c#

I would like to know how to add item to the dictionary from the first foreach loop and the second foreach loop at the same time..
For example - the first loop adds the first contents to the item and starts the second loop which I want it to add the first item in the loop and then starts the outside loop without reading the second item. Do the same and add the second item from the second loop.
Sorry if the question is confusing..Weak english.
List<object> items = new List<object>();
DeviceSettings deviceSettings = new DeviceSettings();
List<object> deviceName = deviceSettings.GetMonitorFriendlyName();
using (ManagementObjectCollection moc = searcher.Get())
{
foreach (ManagementObject mo in moc)
{
Dictionary<string, object> item = new Dictionary<string, object>();
ConnectedMonitor_Number = searcher.Get().Count;
item.Add("DefaultMonitorLength", DefaultMonitor_Width);
item.Add("DefaultMonitorHeight", DefaultMonitor_Height);
item.Add("ConnectedMonitor_Numb", Convert.ToString(ConnectedMonitor_Number));
item.Add("Caption", Convert.ToString(mo["Caption"]));
item.Add("Name", Convert.ToString(mo["Name"]));
item.Add("Description", Convert.ToString(mo["Description"]));
item.Add("DeviceID", Convert.ToString(mo["DeviceID"]));
item.Add("Manufacturer", Convert.ToString(mo["Manufacturer"]));
string[] HardwareID = (string[])mo["HardwareID"];
item.Add("HardwareID", string.Join(";", HardwareID));
item.Add("Status", Convert.ToString(mo["Status"]));
foreach (Dictionary<string, string> dm in deviceName)
{
item["monitorname"] = Convert.ToString(dm["monitorname"]);
}
items.Add(item);
}
}
---This is the devicesettings.cs ---
public static string MonitorFriendlyName(LUID adapterId, uint targetId)
{
DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME();
deviceName.header.size = (uint)Marshal.SizeOf(typeof(DISPLAYCONFIG_TARGET_DEVICE_NAME));
deviceName.header.adapterId = adapterId;
deviceName.header.id = targetId;
deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
int error = DisplayConfigGetDeviceInfo(ref deviceName);
if (error != ERROR_SUCCESS)
throw new Win32Exception(error);
return deviceName.monitorFriendlyDeviceName;
}
public List<object> GetMonitorFriendlyName()
{
try
{
List<object> items = new List<object>();
uint PathCount, ModeCount;
int error = GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS,
out PathCount, out ModeCount);
if (error != ERROR_SUCCESS)
{
throw new Win32Exception(error);
}
DISPLAYCONFIG_PATH_INFO[] DisplayPaths = new DISPLAYCONFIG_PATH_INFO[PathCount];
DISPLAYCONFIG_MODE_INFO[] DisplayModes = new DISPLAYCONFIG_MODE_INFO[ModeCount];
error = QueryDisplayConfig(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS,
ref PathCount, DisplayPaths, ref ModeCount, DisplayModes, IntPtr.Zero);
for (int i = 1; i < ModeCount; i++)
{
if (DisplayModes[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET)
{
Dictionary<string, string> item = new Dictionary<string, string>();
item["MonitorName"] = (MonitorFriendlyName(DisplayModes[i].adapterId, DisplayModes[i].id));
items.Add(item);
}
}
return items;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}

You appear to be overwriting your monitorname key in your dictionary entry every time you iterate. This would set every single item to have the same monitor name. Try something like this:
List<object> items = new List<object>();
DeviceSettings deviceSettings = new DeviceSettings();
List<object> deviceNames = deviceSettings.GetMonitorFriendlyName();
using (ManagementObjectCollection moc = searcher.Get())
{
var managementObjects = moc.Cast<ManagementObject>().ToArray();
ConnectedMonitor_Number = managementObjects.Length;
for (int i = 0; i < managementObjects.Length; i++)
{
object device = deviceNames[i];
ManagementObject mo = managementObjects[i];
Dictionary<string, object> item = new Dictionary<string, object>
{
{ "DefaultMonitorLength", DefaultMonitor_Width },
{ "DefaultMonitorHeight", DefaultMonitor_Height },
{ "ConnectedMonitor_Numb", Convert.ToString(ConnectedMonitor_Number) },
{ "Caption", Convert.ToString(mo["Caption"]) },
{ "Name", Convert.ToString(mo["Name"]) },
{ "Description", Convert.ToString(mo["Description"]) },
{ "DeviceID", Convert.ToString(mo["DeviceID"]) },
{ "Manufacturer", Convert.ToString(mo["Manufacturer"]) },
{ "HardwareID", string.Join(";", (string[])mo["HardwareID"]) },
{ "Status", Convert.ToString(mo["Status"]) },
{ "monitorname", Convert.ToString(device["monitorname"])}
};
items.Add(item);
}
}
Note this doesn't compile because you are declaring deviceNames as a List<object> however appear to treat it like a Dictionary<string,string>. Is there a cast we're not seeing? Also this answer is predicated on the assumption you're searching only for connected monitors.
Update:
Seeing where you copied your source from, you need to revert your code back to what the original author was doing. If you really want a dictionary, you'll need to pick a key that you can tie into your WMI search results from above.

If I got your question this may be logic you looking for(Not sure). Use an outer loop to just hold item and an inner loop to do a real operation.
foreach (ManagementObject mo in moc)
{
foreach (item-no-n mo in ManagementObject )
{
///1st item loop to n-item
}
foreach (item-no-n mo in ManagementObject )
{
///1st item loop to n-item
}
}

Edit after looking at the updated code.
Your code seems to be all messed up and I am sure it is not even executing completely.
You are using same Key for dictionary (Dictionary<string, string> item) in your list of Dictionaries (List<object> items). This means, at any given time, you have exactly one value in your dictionary. What are you trying to achieve by this?
Now, coming to your question where you are trying to loop through the second foreach just once and exit.
I am seeing a major issue here. You are trying to access value of the key "monitorname" whereas, at the source, you are assigning the value to key "MonitorName".
Based on your Dictionary initialisation, keys in your Dictionary are case-sensitive, and here you are trying to access wrong key.
Since you always have a single entry in the dictionary with key "MonitorName", this line of code will throw KeyNotFoundException at runtime.
But you have reported that adding break; to the second foreach breaks the first foreach. My guess is that you have not even debugged the code and have posted your question on assumption based on the output you are getting. Which is caused due to runtime exception and not because the break; is not working as expected.
Although there are many things unclear in your code, I am assuming you have a valid reason to have them that way.
The below code should fix your problem:
foreach (Dictionary<string, string> dm in deviceName)
{
item["monitorname"] = Convert.ToString(dm["MonitorName"]);
break;
}
Notice dm["MonitorName"] where I have updated the key from "monitorname" to "MonitorName".
Also remember to use correct key while accessing item["monitorname"]
Hope this helps!

Related

Check if List<string> exists

This is my code
List<string> list = new List<string>() { "bfd", "jy", "aaaaa", "ndnk", "ntfn", "gfm", "gfm", "mhgd5h", "srsr", "ntr", "mtmyt", "dmy", "mmy6", "ngn9d", "y6m1", "d8dm", "bbbbb", "tym", "dmj", "trsh", "tsr"};
List<string> test = new List<string>() {"aaaaa","bbbbb","ccccc","ddddd","eeeee","fffff","ggggg" };
foreach (var a in list)
{
foreach (var i in test)
{
if (i.StartsWith(a) == false)
{
Console.WriteLine(i);
}
}
}
I want to output from the list and match in the test. If the test exists, then it will not be displayed. If there is no side output,But there may be a problem with my code, it will output the same value many times
The list contains aaaaa, according to logic, aaaaa should not be output
Try this:
List<string> list = new List<string>(){"bfd", "jy", "aaaaa", "ndnk", "ntfn", "gfm", "gfm", "mhgd5h", "srsr", "ntr", "mtmyt", "dmy", "mmy6", "ngn9d", "y6m1", "d8dm", "bbbbb", "tym", "dmj", "trsh", "tsr"};
List<string> test = new List<string>(){"aaaaa", "bbbbb", "ccccc", "ddddd", "eeeee", "fffff", "ggggg"};
foreach (var a in list)
{
if (!test.Contains(a))
{
Console.WriteLine(a);
}
}
There are simple solutions using LINQ. But since I assume this is an exercise, I will show you the detailed version using loops.
The problem is that the WriteLine is inside the inner loop. Therefore you will get many repetitions. Store the outcome of the test in a Boolean variable and place the display part after the inner loop.
foreach (var a in list)
{
bool found = false;
foreach (var i in test)
{
if (i.StartsWith(a))
{
found = true;
break; // Exit the inner loop
}
}
if (!found)
{
Console.WriteLine(a); // We must output a here since i out of scope.
}
}
Also, if you want to know whether a specific string is contained in the list, you should probably replace i.StartsWith(a) with i == a.
The code becomes easier to read, if you extract the list search into its own method
private bool IsInList(List<string> list, string item)
{
foreach (string s in list)
{
if (s == item)
{
return true;
}
}
return false;
}
Now, you don't need the Boolean variable any more
foreach (var a in list)
{
if (!IsInList(test, a))
{
Console.WriteLine(a);
}
}
I used !condition (pronounce: "not condition") instead of condition == false. It's terser.
I assume that this is an exercise. In production code you would simply use the built in method Contains of the list.
foreach (var a in list)
{
if (!test.Contains(a))
{
Console.WriteLine(a);
}
}
or even (as #mjwills suggests in his comment):
foreach (var a in list.Except(test)) {
Console.WriteLine(a);
}

How to access properties of the object type c#?

var obj1 = new A()
{
Name = "abc",
Id = 1
}
var obj2 = new B()
{
Place = "XYZ",
Pincode = 123456
}
var obj3 = new C()
{
Mark = 100,
Standard = "Tenth"
}
var myList = new List<object>();
myList .add(obj1);
myList .add(obj2);
myList .add(obj3);
This is my code structure. I need to access the properties of the myList object. i.e) I need to access the properties like Name, Id, Place, Pincode, Mark, Standard from the myList object and it's corresponding values.
How to achieve it?
As I wrote in my comment, usually keeping completely different types in the same collection is wrong. However, that doesn't mean that's always the case, and so assuming you have a good enough reason to do that - here's one option to do it.
Assuming c# 7 or higher, your best option would probably be to (ab)use switch with pattern matching:
foreach(var obj in myList)
{
switch(obj)
{
case A a:
DoSomethingWithA(a);
break;
case B b:
DoSomethingWithB(b);
break;
}
}
You can try something like below. Working code here
public static List<List<string>> GetProperties(List<object> myList)
{
// If you don't want two lists, you can use Dictionary<key, value>
List<string> props = new List<string>();
List<string> values = new List<string>();
foreach (var a in myList)
{
if(a == null)
continue;
var propsInfo = a.GetType().GetProperties();
foreach (var prop in propsInfo)
{
if(!props.Contains(prop.Name))
{
props.Add(prop.Name);
values.Add(prop.GetValue(a, null).ToString());
}
}
}
return new List<List<string>> { props, values};
}
If you are simply looking to get values out of an object (property values), that is a different story.
foreach (objectType obj in mylist)
{
someVariable1 = obj.name;
someVariable2 = obj.Id;
}
Here is some code I use to compare two objects. I don't know if this is your scenario but I hope it helps you get what you need it for.
protected List<string> GetProperties(List<object> myList)
{
List<string> props = new List<string>();
foreach (var a in myList)
{
if(a == null)
continue;
var propsInfo = a.GetType().GetProperties();
foreach (var prop in propsInfo)
{
if(!props.Contains(prop.Name))
{
props.Add(prop.Name);
}
}
}
return props;
}

Iterate over dictionary values list in C# to check for specific key

I would like to iterate over dictionary values which is a list of strings in C# to check for all keys
Dictionary<string, List<string>> csvList = new Dictionary<string, List<string>>();
I want to check each key(string) in csvList and check if it exists in any values(List)
foreach(var events in csvList)
{
foreach(var action in csvList.Values) // But I want to loop through all the lists in dictionary, not just the list of event key
{
}
}
This is kind of strange but let's try to work through it. We don't usually want to iterate the keys of a dictionary. The reason to use one is we want to get the values very quickly if we already know the key.
In the spirit of answering the question, to iterate over a Dictionary's keys you have to use the Keys property. Note that nothing about the order of this collection is guaranteed.
var d = new Dictionary<string, int>();
d.Add("one", 1);
d.Add("two", 2);
foreach (var k in d.Keys) {
Console.WriteLine(k);
}
But I think maybe you had a problem and chose a Dictionary as the solution, then came here when that didn't work. What if the Dictionary isn't the problem?
It sounds like you have several List<string> instances and you're interested in if a particular list contains a particular string. Or maybe you want to know, "Which lists contain which string?" We can answer that with a dictionary structured slightly differently. I'm going to use arrays instead of lists because it's easier to type.
using System;
using System.Collections.Generic;
public class Program
{
private static void AddWord(Dictionary<string, List<int>> d, string word, int index) {
if (!d.ContainsKey(word)) {
d.Add(word, new List<int>());
}
d[word].Add(index);
}
private static List<int> GetIndexesForWord(Dictionary<string, List<int>> d, string word) {
if (!d.ContainsKey(word)) {
return new List<int>();
} else {
return d[word];
}
}
public static void Main()
{
var stringsToFind = new[] { "one", "five", "seven" };
var listsToTest = new[] {
new[] { "two", "three", "four", "five" },
new[] { "one", "two", "seven" },
new[] { "one", "five", "seven" }
};
// Build a lookup that knows which words appear in which lists, even
// if we don't care about those words.
var keyToIndexes = new Dictionary<string, List<int>>();
for (var listIndex = 0; listIndex < listsToTest.GetLength(0); listIndex++) {
var listToTest = listsToTest[listIndex];
foreach (var word in listToTest) {
AddWord(keyToIndexes, word, listIndex);
}
}
// Report which lists have the target words.
foreach (var target in stringsToFind) {
Console.WriteLine("Lists with '{0}':", target);
var indices = GetIndexesForWord(keyToIndexes, target);
if (indices.Count == 0) {
Console.WriteLine(" <none>");
} else {
var message = string.Join(", ", indices);
Console.WriteLine(" {0}", message);
}
}
}
}
foreach(var events in csvList)
{
foreach(var action in csvList.Values)
{
if (action.Contains(events.Key)) //Just use this, there is no point to iterate the list as you can use contains method
}
}

How to set LiveCharts StackedColumns labels in the correct order

I am using LiveCharts to create a StackedColumns chart that gets populated from a Dictionary collection like this:
I have only found examples where the labels and the content of the columsn are input hardcoded.
AgvCtlSvcs.AgvErrorHistory[] agvErrorHistory;
AgvError[] agvErrors;
Dictionary<string, int> errorCodes = new Dictionary<string, int>();
Dictionary<string, AgvChartEntry> unsortedAgvCollection = new Dictionary<string, AgvChartEntry>();
Dictionary<string, StackedColumnSeries> stackedColumns = new Dictionary<string, StackedColumnSeries>();
List<string> errors = new List<string>();
List<string> errorsDisplay = new List<string>();
List<string> agvs = new List<string>();
List<string> stations = new List<string>();
foreach (Agv.AgvStatus agv in mw.AgvCtlSvcs.GetAgvStatus())
{
List<AgvCtlSvcs.AgvErrorHistory> query = (from item in agvErrorHistory where agv.AgvID.ToString() == item.AGV select item).ToList();
// Create a collection containing a record for each AGV and
// for each record store home many errors of each type
// occurred for that specific AGV
foreach (AgvCtlSvcs.AgvErrorHistory item in query)
{
// Add the record to the colletion for that AGV if not present
if (!unsortedAgvCollection.ContainsKey(item.AGV))
{
stackedColumns.Add(item.AGV, new StackedColumnSeries { Title = "AGV-" + item.AGV, DataLabels = true });
// add the error to the AGV record
unsortedAgvCollection.Add(item.AGV, new AgvChartEntry { AgvID = item.AGV, Error = new Dictionary<string, int>() });
// set 1 occurrency for that record (initialize it)
unsortedAgvCollection[item.AGV].Error.Add(item.ErrorDesc, 1);
}
else
{
// If this record already stored for that AGV, increment occurrency
if (unsortedAgvCollection[item.AGV].Error.ContainsKey(item.ErrorDesc))
{
unsortedAgvCollection[item.AGV].Error[item.ErrorDesc]++;
}
// set 1 occurrency for that record (initialize it)
else
{
unsortedAgvCollection[item.AGV].Error.Add(item.ErrorDesc, 1);
}
}
// create a record for that error in the errors code collection
if (!errors.Contains(item.ErrorCode))
{
errors.Add(item.ErrorCode);
}
// create a record for that error in the errors description collection
if (!errorsDisplay.Contains(item.ErrorDesc))
{
errorsDisplay.Add(item.ErrorDesc);
}
}
}
// Initialize the values of the columns to int
foreach (KeyValuePair<string, StackedColumnSeries> item in stackedColumns)
{
item.Value.Values = new ChartValues<int>();
}
// clear labels collection
for (int i = AgvChartLabels.Count - 1; i >= 0; i--)
{
AgvChartLabels.RemoveAt(i);
}
// for each type of error that occurred check for each AGV in the agvCollection
// if that specific AGV had this error, if so add a column for that error with the
// occurrency value
foreach (KeyValuePair<string, AgvChartEntry> agv in unsortedAgvCollection)
{
foreach (string error in errorsDisplay)
{
if (agv.Value.Error.ContainsKey(error))
{
stackedColumns[agv.Key].Values.Add(agv.Value.Error[error]);
}
}
}
foreach (var error in errorsDisplay)
{
if (!AgvChartLabels.Contains(error))
{
AgvChartLabels.Add(error);
}
}
// add to the series collection the columns (AGVs) that contains at least a value (error)
foreach (KeyValuePair<string, StackedColumnSeries> item in stackedColumns)
{
if (item.Value.Values.Count > 0)
{
AgvSeriesCollection.Add(item.Value);
}
}
my problem is that the labels on the X axis don not correspond to the right column.
How can I set the labels in the correct order according to the columns?
I have tried all kind of solution but I can't figure it out.
What am I missing?
The problem was that I was not adding the "zero" values to the StackedColumnsSeries so all the values where compressed to the left of the chart and the labels where wrong.
foreach (KeyValuePair<string, AgvChartEntry> agv in unsortedAgvCollection)
{
foreach (string error in errorsDisplay)
{
if (agv.Value.Error.ContainsKey(error))
{
stackedColumns[agv.Key].Values.Add(agv.Value.Error[error]);
}
else
{
//Must add the zero value it the entry does not exist
stackedColumns[agv.Key].Values.Add(0);
}
}
}

Prevent collection modified exception in a foreach loop in c#

I'm iterating over a dictionary Dictionary<double, int> diametersAndQuantities and the dictionary is modified. Obviously I'm getting an exception that the collection has been modified. How can I prevent this from happening?
foreach (var diametersAndQuantity in diametersAndQuantities)
{
// some operations here
// update
diametersAndQuantities[db] = n;
}
You can create a temporary list of the KeyValuePairs to iterate over and still update the dictionary.
foreach (var diametersAndQuantity in diametersAndQuantities.ToList())
{
// some operations here
// update
diametersAndQuantities[diametersAndQuantity.Key] = n;
}
you can use the ToList() to get the enumeration to be evaluated
similar to accepted answer - maybe a little faster
should use less memory
Dictionary<int, int> dic = new Dictionary<int, int>() { { 1, 2 }, { 2, 3 }, { 3, 2 } };
foreach (int value in dic.Values)
Debug.WriteLine(value);
foreach (int key in dic.Keys.ToList())
dic[key] = 12;
foreach (int value in dic.Values)
Debug.WriteLine(value);
Debug.WriteLine("done");

Categories