Getting an elements variable name in foreach loop - c#

Is it possible to get an elements variable name in a foreach loop? I have tried nameof(v), which does not seem to work. See below:
//check for blank answer boxes and set flag for validation
foreach (string v in new object[] { answer3, answer4, answer5, answer6b, answer11, answer12, answer13b, answer14c, answer18, answer20 })
{
if (string.IsNullOrWhiteSpace(v))
{
s1.Flag = true;
s1.FlagContent += $"Blank answer box: {nameof(v)}. ";
}
}
For example, if answer3 was null or contained white space, s1.Flag would be set to true and s1.FlagContent would be set to "Blank answer box: answer3".

What you're asking is not possible. And when you consider that a given object may be referenced by any number of variables (all of which could have different names), this idea doesn't even make sense.
The typical way to handle this sort of scenario is to store the answers in a dictionary instead of giving them separate variables. If you absolutely have to have them in separate variables, you can convert them to a dictionary like this:
var dictionary = new Dictionary<string, string>
{
{ "answer1", answer1 },
{ "answer2", answer2 },
{ "answer3", answer3 },
{ "answer4", answer4 },
{ "answer5", answer5 }
};
Then the problem is trivial:
foreach (var item in dictionary)
{
if (string.IsNullOrWhiteSpace(item.Value))
{
s1.Flag = true;
s1.FlagContent += $"Blank answer box: {item.Key}.";
}
}

use a Dictionary:
string answer3 = "bla";
string answer4 = null;
string answer5 = "";
var answers = new Dictionary<string,string>();
answers.Add( nameof(answer3), answer3 );
answers.Add( nameof(answer4), answer4 );
answers.Add( nameof(answer5), answer5 );
foreach( var v in answers )
{
if (string.IsNullOrWhiteSpace(v.Value))
{
s1.Flag = true;
s1.FlagContent += $"Blank answer box: {v.Key}. ";
}
}

Related

separating strings by some text within listbox

I have a ListBox where table names are written like this:
Staging_Section_01_2019_03_19_01
Staging_Section_01_2019_03_20_01
Staging_Section_23_2019_03_21_01
Staging_Section_52_2019_03_23_01
Staging_Section_52_2019_03_24_01
What I am trying to do is to separate them by Section Number, so I want all Section_01 in one List object and Section_23 in another List object, so on and so forth. The dynamic nature is whats making it difficult for me.
So far, I have the following:
foreach (var it in uploadBox.Items)
{
if (it.ToString().Contains("Section"))
{
section = it.ToString().Substring(0, 18);
found = it.ToString().IndexOf("_");
section = section.Substring(found + 1);
sectionNum = section.Substring(8, 2);
}
}
I have gotten the sectionNum which would just be the number and section, which is the string like Section_01.
Any idea on how to approach this?
The expected output would be something like this:
List 1
Staging_Section_01_2019_03_19_01
Staging_Section_01_2019_03_20_01
List 2
Staging_Section_23_2019_03_21_01
List 3
Staging_Section_52_2019_03_23_01
Staging_Section_52_2019_03_24_01
I would use a Dictionary<string, List<string>> for this. Each 'section' that is parsed would be a key, and the remaining portion would the the value.
Dictionary<string, List<string>> myDict = new Dictionary<string, List<string>>();
foreach (var it in uploadBox.Items)
{
if (it.ToString().Contains("Section"))
{
section = it.ToString().Substring(0, 18);
found = it.ToString().IndexOf("_");
section = section.Substring(found + 1);
sectionNum = section.Substring(8, 2);
if(!myDict.ContainsKey(sectionNum))
{
myDict.Add(sectionNum, new List<string> { someOtherValue });
}
else
{
myDict[sectionNum].Add(someOtherValue);
}
}
}
Unless I have completely misinterpreted your question, I think this is a potential solution to your dynamic objects.
you could do something like this:
var sections = new Dictionary<string, List<string>>();
foreach(var it in uploadBox.Items)
{
var item = it.ToString();
if(item.Contains("Section"))
{
var section = GetSection(item);
if(!sections.ContainsKey(section))
{
sections.Add(section, new List<string>());
}
sections[section].Add(item);
}
}
private string GetSection(string item)
{
var split = item.Split("_");
return $"{split[1]}_{split[2]}";
}
It is best to regex for this kind of task:
uploadBox.Items
.GroupBy(x => Regex.Match(x.ToString(), #"^\w+_Section_(?<section>\d+)").Groups["section"].Value)

How to populate KeyValuePair<int, int> inside a foreach loop

I have this code snippet as below which iterates over a split string.
if (!string.IsNullOrEmpty(profile.ContactNumber))
{
var splitContract = profile.ContactNumber.Split(new string[] { "and", "&" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var contract in splitContract)
{
//check the split if it contains "x" or "X" character - if it does contain, it means it's a valid contract
if (contract.Contains("x") || contract.Contains("X"))
{
var condensedString = contract.Replace(" ", "");
var split = condensedString.Split(new char[] { 'x', 'X' });
GetNumbersOnly(split);
}
}
}
private void GetNumbersOnly(string[] inputArray)
{
var ListKeyValuePair = new List<KeyValuePair<string, string>>();
foreach (var item in inputArray)
{
var numberToAdd = Regex.Replace(item, "[^0-9]", "", RegexOptions.None);
ListKeyValuePair.Add(?, ?);
}
}
In GetNumbersOnly method, how can I populate List of KeyValuePair inside the for each loop?
The inputArray variable has an array element of [0] = 100, [1] = 5 for the first iteration and so on.
This is the desired output for the KeyValuePair {100, 5}, {200, 10}, {500, 15}.
Sorry, I can't seem to find any related scenario when I googled it. Any help with this is greatly appreciated.
Because the key and value are stored in separate array items, your logic is dependent on order. In cases like this, you should avoid for...each and instead use plain old for, which allows you to control the manner of iteration.
private void GetNumbersOnly(string[] inputArray)
{
var ListKeyValuePair = new List<KeyValuePair<string, string>>();
for (int i=0; i< inputArray.Length; i+=2) //The "2" here is very important!
{
var numberToAdd1 = Regex.Replace(inputArray[i], "[^0-9]", "", RegexOptions.None);
var numberToAdd2 = Regex.Replace(inputArray[i+1], "[^0-9]", "", RegexOptions.None);
ListKeyValuePair.Add(new KeyValuePair<string, string>(numberToAdd1, numberToAdd2));
}
}
The ListKeyValuePair.Add( ) function is expecting 1 field which is of type KeyValuePair. You need to make one of these with a new KeyValuePair() { key = item, value = numberToAdd };
Why are you keeping key value pairs in a list? Why not a Dictionary ? Do you want duplicate pairs?

Get string from another string array if value matches

String Array 1: (In this format: <MENU>|<Not Served?>|<Alternate item served>)
Burger|True|Sandwich
Pizza|True|Hot Dog
String Array 2: (Contains Menu)
Burger
Pizza
Grill Chicken
Pasta
I need the menu is served or any alternate item served for that particular item.
Code:
for(int i = 0; i < strArr2.Length; i++)
{
if(strArr2.Any(_r => _r.Split('|').Any(_rS => _rS.Contains(strArr1[i]))))
{
var menu = strArr2[i];
var alternate = ? // need to get alternate item
}
}
As I commented in the code, how to get the alternate item in that string array? Please help, thanks in advance.
P.S: Any help to trim if condition is also gladly welcome.
Instead of any, you may use Where to get the value matching.
#Markus is having the detailed answer, I am just using your code to find a quick fix for you.
for(int i = 0; i < strArr2.Length; i++)
{
if(strArr2.Any(_r => _r.Split('|').Any(_rS => _rS.Contains(strArr1[i]))))
{
var menu = strArr2[i];
var alternate = strArr2.Where(_rs => _rs.Split('|').Any(_rS => _rS.Contains(strArr1[i]))).First().Split('|').Last();
}
}
In order to simplify your code, it is a good idea to better separate the tasks. For instance, it will be much easier to handle the contents of string array 1 after you have converted the contents into objects, e.g.
class NotServedMenu
{
public string Menu { get; set; }
public bool NotServed { get; set; }
public string AlternateMenu { get; set; }
}
Instead of having an array of strings, you can read the strings to a list first:
private IEnumerable<NotServedMenu> NotServedMenusFromStrings(IEnumerable<string> strings)
{
return (from x in strings select ParseNotServedMenuFromString(x)).ToArray();
}
private NotServedMenu ParseNotServedMenuFromString(string str)
{
var parts = str.Split('|');
// Validate
if (parts.Length != 3)
throw new ArgumentException(string.Format("Unable to parse \"{0}\" to an object of type {1}", str, typeof(NotServedMenu).FullName));
bool notServedVal;
if (!bool.TryParse(parts[1], out notServedVal))
throw new ArgumentException(string.Format("Unable to read bool value from \"{0}\" in string \"{1}\".", parts[1], str));
// Create object
return new NotServedMenu() { Menu = parts[0],
NotServed = notServedVal,
AlternateMenu = parts[2] };
}
Once you can use the objects, the subsequent code will be much cleaner to read:
var notServedMenusStr = new[]
{
"Burger|True|Sandwich",
"Pizza|True|Hot Dog"
};
var notServedMenus = NotServedMenusFromStrings(notServedMenusStr);
var menus = new[]
{
"Burger",
"Pizza",
"Grill Chicken",
"Pasta"
};
var alternateMenus = (from m in menus join n in notServedMenus on m equals n.Menu select n);
foreach(var m in alternateMenus)
Console.WriteLine("{0}, {1}, {2}", m.Menu, m.NotServed, m.AlternateMenu);
In this sample, I've used a Linq join to find the matching items.
You could do something like that
string[] strArr1 = { "Burger|True|Sandwich", "Pizza|True|Hot Dog" };
string[] strArr2 = { "Burger", "Pizza", "Grill Chicken", "Pasta" };
foreach (string str2 in strArr2)
{
string str1 = strArr1.FirstOrDefault(str => str.Contains(str2));
if (str1 != null)
{
string[] splited = str1.Split('|');
string first = splited[0];
bool condition = Convert.ToBoolean(splited[1]);
string second = splited[2];
}
}

Combine two list values into one

is there a way to combine these to list items into one list item ? i am sorry if this is a begginer mistake
List<string> values = new List<string>();
foreach (Feature f in allFeatures)
{
if (f.ColumnValues.ContainsKey(layercode)&& f.ColumnValues.ContainsKey(layercode2))
{
if (!values.Contains(f.ColumnValues[layercode].ToString()) && !values.Contains(f.ColumnValues[layercode2].ToString()))
{
values.Add(f.ColumnValues[layercode].ToString());
values.Add(f.ColumnValues[layercode2].ToString());
}
}
}
You can use a List of Tuples, a Dictionary, or create a class. I will not go into depth explaining these as you should be able to easily search and find other questions all about these. Some of this is from memory so syntax might be a bit off.
List of Tuples
List<Tuple<string,string>> values = new List<Tuple<string,string>>();
//...
if ( !values.Any(v=>v.Item1 == f.ColumnValues[layercode].ToString()) && !values.Any(v=>v.Item2 == f.ColumnValues[layercode2].ToString()) )
{
values.Add( Tuple.Create(f.ColumnValues[layercode].ToString(),
f.ColumnValues[layercode2].ToString()) );
}
Dictionary
Dictionary<string,string> values = new Dictionary<string,string> ();
//...
if (!values.ContainsKey(f.ColumnValues[layercode].ToString()) && !values.ContainsValue(f.ColumnValues[layercode2].ToString()))
{
values[f.ColumnValues[layercode].ToString()] = f.ColumnValues[layercode2].ToString();
}
List of class instances
public class LayerCodePair {
public string Code1 {get;set;}
public string Code2 {get;set;}
} // declared outside of method
...
List<LayerCodePair> values = new List<LayerCodePair>();
//...
if (!values.Any(v=> v.Code1 == f.ColumnValues[layercode].ToString()) && !values.Any(v=>v.Code2 == f.ColumnValues[layercode2].ToString()))
{
values.Add(new LayerCodePair{
Code1 = f.ColumnValues[layercode].ToString(),
Code2 = f.ColumnValues[layercode2].ToString()
});
}
It should work for you, using ";" character as a separator:
List<string> values = new List<string>();
foreach (Feature f in allFeatures)
{
var columnValues = f.ColumnValues;
var firstLayerCode = columnValues[layercode].ToString();
var secondLayerCode = columnValues[layercode2].ToString();
if (columnValues.ContainsKey(layercode) && columnValues.ContainsKey(layercode2))
{
if (!values.Contains(firstLayerCode) && !values.Contains(secondLayerCode))
{
var combinedValue = firstLayerCode + ";" + secondLayerCode;
values.Add(combinedValue);
}
}
}

Creating objects dynamically in loop

I have an array of strings that I am looping through. I would like to loop through the array and on each iteration, create a new object with a name that matches the string value.
For example;
string[] array = new string[] { "one", "two", "three" };
class myClass(){
public myClass(){
}
}
foreach (string name in array)
{
myClass *value of name here* = new myClass();
}
Would result in three objects being instantiated, with the names "one", "two" and "three".
Is this possible or is there are better solution?
What are you trying to do is not possible in statically-typed language. IIRC, that's possible on PHP, and it's not advisable though.
Use dictionary instead: http://ideone.com/vChWD
using System;
using System.Collections.Generic;
class myClass{
public string Name { get; set; }
public myClass(){
}
}
class MainClass
{
public static void Main()
{
string[] array = new string[] { "one", "two", "three" };
IDictionary<string,myClass> col= new Dictionary<string,myClass>();
foreach (string name in array)
{
col[name] = new myClass { Name = "hahah " + name + "!"};
}
foreach(var x in col.Values)
{
Console.WriteLine(x.Name);
}
Console.WriteLine("Test");
Console.WriteLine(col["two"].Name);
}
}
Output:
hahah one!
hahah two!
hahah three!
Test
hahah two!
While others have given you an alternate but no one is telling why do they recommend you that.
That's because You cannot access object with dynamic names.
(Food for thought: Just think for a moment if you could do so, how will you access them before they are even coded/named.)
Instead create a Dictionary<string, myClass> as others mentioned.
Use a Dictionary<String, myClass> instead:
var dict= new Dictionary<String, myClass>();
foreach (string name in array)
{
dict.Add(name, new myClass());
}
Now you can access the myClass instances by your names:
var one = dict["one"];
or in a loop:
foreach (string name in array)
{
myClass m = dict[ name ];
}
You can use this approach:
var array = [srt1, srt2, str3];
var other_array = [];
for(var i = 0; i < array.length; i++){
other_array.push({
name: array[i]
})
}
And for lookup it is easy to find the instance you need by filtering:
var instance1 = other_array.filter(function(result) {
return result.name == 'str1';
});
Looks like you need a list of dictionary of your objects:
var myClassDictionary = new Dictionary<string,myClass>();
foreach (string name in array)
{
myClassDicationry.Add(name, new myClass());
}
// usage:
// myClass["one"] <- an instance of myClass
There are no programming languages that I know of that let you define variable names in runtime.
You could do something like this -
Dictionary<string, myClass> classes = new Dictionary<string, myClass>();
foreach(string name in array)
{
classes[name] = new myClass();
}
Then you can refer to the named instances later
classes[name].MyClassMethod();
You can use the following code.
string[] array = new string[] { "one", "two", "three" };
Dictionary<String, myClass> list;
class myClass(){
public myClass(){
list = new Dictionary<String, myClass>();
}
}
foreach (string name in array)
{
list.Add(name, new myClass())
}
You can use lists to store the objects so you can access them
list<myClass> myClasses = new List<myClass>();
foreach (myClass object in myClasses)
{
//preform interaction with your classes here
}
Not applicable to C#, or any statically-typed language for that matter.
For curiosity, I tried if what I remembered in PHP(creating variables on-the-fly) is still correct.
It's still the same PHP, last I used it was year 2000. You can generate variables on-the-fly, not saying it's advisable though, it pollutes the global variables, it can corrupt some existing variable or object with same name.
https://ideone.com/nJDiou
<?php
class MyClass
{
private $v;
function __construct($x) {
$this->v = $x;
}
public function getValue() {
return $this->v;
}
}
$one = new MyClass("I'm tough!");
echo "The one: " . $one->getValue() . "\n";
$i = 0;
foreach(array("one","two","three") as $h) {
$$h = new MyClass("Says who? " . ++$i);
}
echo "The one: " . $one->getValue() . "\n";
echo $two->getValue() . "\n";
echo $three->getValue() . "\n";
echo "loop\n";
foreach(array("three","one","two") as $h) {
echo $$h->getValue() . "\n";
}
?>
Outputs:
The one: I'm tough!
The one: Says who? 1
Says who? 2
Says who? 3
loop
Says who? 3
Says who? 1
Says who? 2

Categories

Resources