Putting a field to the next empty array index - c#

How can I put a string to the next empty index in a string array? I want to use a foreach loop and see if all the boolean strings are valid bools, and then put the keys of the invalid boolean strings to an array
string[] invalidKeys;
foreach (string key in ConfigurationManager.AppSettings)
{
string value = ConfigurationManager.AppSettings[key];
if (IsValidBooleanString(value) == false)
{
//Add 'key' to next empty index in the array 'invalidKeys'.
}
return invalidKeys;

You haven't initialized or specified the length of the array. You need to specify the length for the Array to create one, but in your case you don't know that info in advance
So you can use a List instead
var invalidKeys = new List<String>();
foreach (string key in ConfigurationManager.AppSettings.Keys)
{
string value = ConfigurationManager.AppSettings[key];
if (IsValidBooleanString(value) == false)
{
//Add 'key' to next empty index in the array 'invalidKeys'.
invalidKeys.Add(key);
}
return invalidKeys;
Also noticed your foreach should be on ConfigurationManager.AppSettings.Keys not ConfigurationManager.AppSettings
Other way of doing this will be
var invalidKeys =
ConfigurationManager.AppSettings.Keys
.Where(k => IsValidBooleanString(ConfigurationManager.AppSettings[k]) == false)
.ToArray();

If you really want to become a C# programmer:
return (from string key in ConfigurationManager.AppSettings
where !IsValidBooleanString(ConfigurationManager.AppSettings[key])
select key).ToList();
Or ToArray() or whatever.

The functionality of IsValidBooleanString() may be useful elsewhere. I would recommend placing it in an extension class:
public static class StringExtender
{
static readonly string[] validBooleanStrings = { "True", "False", "Yes", "No" };
public static bool IsValidBooleanString(this string value)
{
return ValidBooleanStrings.Contains(value, StringComparer.OrdinalIgnoreCase);
}
}
Some will say it's overkill to create an extension class for a single method, but it's really not and it makes your code modular and reusable. Not to mention you can add more extension methods here as you encounter similar scenarios.
Now all string objects have a .IsValidBooleanString() method attached to them and automatically pass themselves (this) to it. MSDN: Extension Methods (C#)
For retreiving a list of all setting keys with invalid boolean string values, I would use a LINQ query:
var settings = ConfigurationManager.AppSettings;
// Gets all the keys for values that are invalid boolean strings.
var invalidKeys = from key in settings.Keys
where !settings[key].IsValidBooleanString()
select key;
// If you want a list...
var invalidKeyList = invalidKeys.ToList<string>();
// If you want an array...
var invalidKeyArray = invalidKeys.ToArray<string>();
LINQ queries return IEnumerable<> values based on what you give it. Since I am selecting on a string type (key), it knows to give me back an IEnumerable<string>. You can then create a List<string> or string[] from the results if you wish.

Related

Clean Way to Merge Two Typed C# Objects Based on Given Sequence

I have two lists, each containing two objects of a class called TestData
TestData td1_a = new TestData("td1", "val11_a", null, "val13_a");
TestData td1_b = new TestData("td1", "val11_b", "val12_b", null);
TestData td2_a = new TestData("td2", "val21_a", "val22_a", null);
TestData td2_b = new TestData("td2", "val21_b", null, "val23_b");
List<TestData> list_a = new List<TestData>() {td1_a, td2_a};
List<TestData> list_b = new List<TestData>() {td1_b, td2_b};
TestData is defined as
public class TestData {
public string DataName;
public string Value1;
public string Value2;
public string Value3;
public TestData(string name, string val1, string val2, string val3) {
DataName = name;
Value1 = val1;
Value2 = val2;
Value3 = val3;
}
}
Note that the two lists each contain two TestData objects whose DataName values are "td1" and "td2"
How to merge the two lists such that the final result would be a single list whose members are two TestData objects where the objects with the same DataName merged and the value of the later override the value of the earlier if it is not null in a clean way?
So if I do mergeList(list_a, list_b), the result would be a list with members of:
TestData td1_merged = new TestData("td1", "val11_b", "val12_b", "val13_a");
TestData td2_merged = new TestData("td2", "val21_b", "val22_a", "val22_b");
That is, _b is replacing _a whenever possible
and if I reverse the order mergeList(list_b, list_a), the result would be a list having member of:
TestData td1_merged = new TestData("td1", "val11_a", "val12_b", "val13_a");
TestData td2_merged = new TestData("td2", "val21_a", "val22_a", "val22_b");
Where _a is replacing _b instead.
At this moment, this is the best I can do with LINQ aggregate:
private List<TestData> mergeList(List<TestData> list_1, List<TestData> list_2) {
return list_1.Concat(list_2) //combining list_1 and list_2 depends on the given sequence
.GroupBy(td => td.DataName) //making groups based on DataName
.Select(g => g.Aggregate(g.First(), (a, b) => { //merge the values of the elements
if (b.Value1 != null) //tedious way of giving the conditions!
a.Value1 = b.Value1;
if (b.Value2 != null)
a.Value2 = b.Value2;
if (b.Value3 != null)
a.Value3 = b.Value3;
return a;
})).ToList();
}
It works fine except for the fact that to make conditions for overriding when not null, I have to write it once for each object. Is there a cleaner way to do it?
Edited:
I do this because I encounter a problem where an object can be partially defined by separated developers on different files. My job is to create, but not to duplicate, the objects created in a smart way such that if the object is defined in more than one file, the later file additional definition will override the early ones, but not overriding everything (what has been defined in the earlier file remains whenever there is no update).
Example, if in one of the file, it is defined:
Chip_ResetSource.bits =[hw_pin=0, power_on=1, missing_clock=2, watchdog=3, software_force=4, comparator=5, convert_start_0=6].
And elsewhere, it is also defined:
Chip_ResetSource =type=uint8;policy=read;
And somewhere else,
Chip_ResetSource =address=2500;unit=count;formula=1;max=255;min=0;
Then I just need to combine all of them. But if in another (later) file there is additional info about Chip_ResetSource:
Chip_ResetSource =address=2501;
Then, while all other info of Chip_ResetSource must remain the same after the third info Chip_ResetSource =address=2500;unit=count;formula=1;max=255;min=0;, its address property must be changed from 2500 to 2501 due to the fourth info.
So, given that problem, I think if I can just create one method to read all the given property at the instantiation and then another method to cleanly merge when other file is read, that will be great!
One approach to simplify your problem would be to use a Dictionary instead of multiple strongly typed classes.
In that case, you would simply add values to the dictionary, and it would update (overwrite) any existing keys with new values:
static void Apply(IDictionary<string, string> properties, string input)
{
// split by semicolon
var props = input.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
// add/merge each key-value pair into the dictionary
foreach (var t in props)
{
var tokens = t.Trim().Split('=');
var key = tokens[0];
var value = tokens[1];
// this will add a new value, or update the existing one
properties[key] = value;
}
}
This would store each value as a separate key-value pair, and you would use this similar to:
var properties = new Dictionary<string, string>();
Apply(properties, "type=uint8;policy=read;");
Apply(properties, "address=2500;unit=count;formula=1;max=255;min=0;");
Apply(properties, "address=2501;");
// dump the contents to screen to see what we've got now
Console.WriteLine(string.Join(";", properties.Select(x => $"{x.Key}={x.Value}")));
Regarding your .bits example, it's not clear whether you would treat .bits as a single string property and overwrite it completely in case it's found in a different file, or update its child properties like it's a nested object.
In this latter case, a simple approach would be to store the child properties exactly the same way, but perhaps prefix their key with "bits.", which would functionally be equivalent to:
Apply(properties, "bits.hw_pin=0; bits.power_on=1; bits.missing_clock=2;");

Check if list contains element that contains a string and get that element

While searching for an answer to this question, I've run into similar ones utilizing LINQ but I haven't been able to fully understand them (and thus, implement them), as I'm not familiarized with it. What I would like to, basically, is this:
Check if any element of a list contains a specific string.
If it does, get that element.
I honestly don't know how I would go about doing that. What I can come up with is this (not working, of course):
if (myList.Contains(myString))
string element = myList.ElementAt(myList.IndexOf(myString));
I know WHY it does not work:
myList.Contains() does not return true, since it will check for if a whole element of the list matches the string I specified.
myList.IndexOf() will not find an occurrence, since, as it is the case again, it will check for an element matching the string.
Still, I have no clue how to solve this problem, but I figure I'll have to use LINQ as suggested in similar questions to mine. That being said, if that's the case here, I'd like for the answerer to explain to me the use of LINQ in their example (as I said, I haven't bothered with it in my time with C#). Thank you in advance guys (and gals?).
EDIT: I have come up with a solution; just loop through the list, check if current element contains the string and then set a string equal to the current element. I'm wondering, though, is there a more efficient way than this?
string myString = "bla";
string element = "";
for (int i = 0; i < myList.Count; i++)
{
if (myList[i].Contains(myString))
element = myList[i];
}
You should be able to use Linq here:
var matchingvalues = myList
.Where(stringToCheck => stringToCheck.Contains(myString));
If you simply wish to return the first matching item:
var match = myList
.FirstOrDefault(stringToCheck => stringToCheck.Contains(myString));
if(match != null)
//Do stuff
The basic answer is: you need to iterate through loop and check any element contains the specified string.
So, let's say the code is:
foreach(string item in myList)
{
if(item.Contains(myString))
return item;
}
The equivalent, but terse, code is:
mylist.Where(x => x.Contains(myString)).FirstOrDefault();
Here, x is a parameter that acts like "item" in the above code.
string result = myList.FirstOrDefault(x => x == myString)
if(result != null)
{
//found
}
for (int i = 0; i < myList.Length; i++)
{
if (myList[i].Contains(myString)) // (you use the word "contains". either equals or indexof might be appropriate)
{
return i;
}
}
Old fashion loops are almost always the fastest.
If you want a list of strings containing your string:
var newList = myList.Where(x => x.Contains(myString)).ToList();
Another option is to use Linq FirstOrDefault
var element = myList.Where(x => x.Contains(myString)).FirstOrDefault();
Keep in mind that Contains method is case sensitive.
You could use Linq's FirstOrDefault extension method:
string element = myList.FirstOrDefault(s => s.Contains(myString));
This will return the fist element that contains the substring myString, or null if no such element is found.
If all you need is the index, use the List<T> class's FindIndex method:
int index = myList.FindIndex(s => s.Contains(myString));
This will return the the index of fist element that contains the substring myString, or -1 if no such element is found.
Many good answers here, but I use a simple one using Exists, as below:
foreach (var setting in FullList)
{
if(cleanList.Exists(x => x.ProcedureName == setting.ProcedureName))
setting.IsActive = true; // do you business logic here
else
setting.IsActive = false;
updateList.Add(setting);
}
You should be able to use something like this, it has worked okay for me:
var valuesToMatch = yourList.Where(stringCheck => stringCheck.Contains(myString));
or something like this, if you need to look where it doesn't match.
var valuesToMatch = yourList.Where(stringCheck => !stringCheck.Contains(myString));
you can use
var match=myList.Where(item=>item.Contains("Required String"));
foreach(var i in match)
{
//do something with the matched items
}
LINQ provides you with capabilities to "query" any collection of data. You can use syntax like a database query (select, where, etc) on a collection (here the collection (list) of strings).
so you are doing like "get me items from the list Where it satisfies a given condition"
inside the Where you are using a "lambda expression"
to tell briefly lambda expression is something like (input parameter => return value)
so for a parameter "item", it returns "item.Contains("required string")" . So it returns true if the item contains the string and thereby it gets selected from the list since it satisfied the condition.
To keep it simple use this;
foreach(string item in myList)//Iterate through each item.
{
if(item.Contains("Search Term")//True if the item contains search pattern.
{
return item;//Return the matched item.
}
}
Alternatively,to do this with for loop,use this;
for (int iterator = 0; iterator < myList.Count; iterator++)
{
if (myList[iterator].Contains("String Pattern"))
{
return myList[iterator];
}
}
It is possible to combine Any, Where, First and FirstOrDefault; or just place the predicate in any of those methods depending on what is needed.
You should probably avoid using First unless you want to have an exception thrown when no match is found. FirstOrDefault is usually the better option as long as you know it will return the type's default if no match is found (string's default is null, int is 0, bool is false, etc).
using System.Collections.Generic;
using System.Linq;
bool exists;
string firstMatch;
IEnumerable<string> matchingList;
var myList = new List<string>() { "foo", "bar", "foobar" };
exists = myList.Any(x => x.Contains("o"));
// exists => true
firstMatch = myList.FirstOrDefault(x => x.Contains("o"));
firstMatch = myList.First(x => x.Contains("o"));
// firstMatch => "foo"
firstMatch = myList.First(x => x.Contains("dark side"));
// throws exception because no element contains "dark side"
firstMatch = myList.FirstOrDefault(x => x.Contains("dark side"));
// firstMatch => null
matchingList = myList.Where(x => x.Contains("o"));
// matchingList => { "foo", "foobar" }
Test this code # https://rextester.com/TXDL57489
I have not seen bool option in other answers so I hope below code will help someone.
Just use Any()
string myString = "test";
bool exists = myList
.Where(w => w.COLUMN_TO_CHECK.Contains(myString)).Any();
You can check the list is empty or not in multiple ways.
1)Check list is null and then check count is greater than zero like below:-
if(myList!=null && myList.Count>0)
{
//List has more than one record.
}
2)Check list null and count greater than zero using linq query like below:-
if(myList!=null && myList.Count>0)
{
//List has more than one record.
}

Dictionary ContainsKey does not seem to work with string[] key

I am trying to have a data structure with multiple string keys. To do this, I tried to create a Dictionary with string[] element. But the ContainsKey do no seem to work as I expect:
Dictionary<string[], int> aaa = new Dictionary<string[], int>();
int aaaCount = 0;
aaa.Add(new string[] { string1, string2 }, aaaCount++);
if (!aaa.ContainsKey(new string[] { string1, string2 }))
{
aaa.Add(new string[] { string1, string2 }, aaaCount++);
}
I see that there are two entries in aaa after the execution of the code above while I was expecting only one. Is this the expected behaviour? How can I ensure that there are no duplicate entries in the Dictionary?
Note: I tried the same with a list as well (List and the result is the same - the Contains method does not really work with string[])
If you want to use string[] as TKey, you should pass IEqualityComparer<string[]> to the constructor of Dictionary. Because Otherwise Dictionary uses standard comparison for TKey and in case of string[] it just compares references hence string[] is reference type. You have to implement IEqualityComparer yourself. It can be done in the following way:
(The implementation is quite naive, I provide it just as the starting point)
public class StringArrayComparer : IEqualityComparer<string[]>
{
public bool Equals(string[] left, string[] right)
{
if (ReferenceEquals(left, right))
{
return true;
}
if ((left == null) || (right == null))
{
return false;
}
return left.SequenceEqual(right);
}
public int GetHashCode(string[] obj)
{
return obj.Aggregate(17, (res, item) => unchecked(res * 23 + item.GetHashCode()));
}
}
You need to create an IEqualityComparer<string[]> and pass it to the dictionary's constructor.
This tells the dictionary how to compare keys.
By default, it compares them by reference.
Because an array is a reference type, i.e., you are checking reference (identity) equality, not equality based on the values within the array. When you create a new array with the same values the arrays themselves are still two distinct objects, so ContainsKey returns false.
Using an array as a Dictionary key is a bit... odd. What are you trying to map here? There is probably a better way to do it.
You may be better off, if your application supports it, to combine the string array into a single string.
We have numerous cases where two pieces of information uniquely identifies a record in a collection and in these cases, we join the two strings using a value that should never be in either string (i.e. Char(1)).
Since it is usually a class instance that is being added, we let the class specify the generation of the key so that the code adding to the collection only has to worry about checking a single property (i.e. CollectionKey).

How to replace value in string array

How to remove my value in String Array and how i can rearrange
public string[] selNames = new string[5];
selNames[0]="AA";
selNames[1]="BB";
selNames[2]="CC";
selNames[3]="DD";
selNames[4]="EE";
In certain Conditaion i need to Check for the existing value and i want to remove it from my collection, How i can do it.
i tried like below, but i cannot, it returns true, but how to make that index value to null
If(selNames .Contains("CC").ToString()==true)
{
// how to make that index null which contains the "CC"; and i need to rearrage the array
}
You can do following.
var newArray = selNames.Where(s => s != "CC").ToArray();
where s is the arg of the Func<TSource, bool> delegate TSource is string in your case.
So it will compare each string in array and return all which is not "СС"
here is a link to msdn
You can use the 'List< T >' for checking the existing values and also can remove the item from the list and also can arrange the list.
The following is the code snippet:
List<string> list = new List<string>();
list.Add("AA");
list.Add("BB");
list.Add("CC");
list.Add("DD");
list.Add("EE");
list.Add("FF");
list.Add("GG");
list.Add("HH");
list.Add("II");
MessageBox.Show(list.Count.ToString());
list.Remove("CC");
MessageBox.Show(list.Count.ToString());

What is the best collection type to easily lookup values with multiple, identical keys?

I have text documents like the following which contain single and multiple variables:
title:: Report #3
description:: This is the description.
note:: more information is available from marketing
note:: time limit for this project is 18 hours
todo:: expand the outline
todo:: work on the introduction
todo:: lookup footnotes
I need to iterate through the lines of this text document and fill a collection with these variables, currently I'm using a Dictionary:
public Dictionary<string, string> VariableNamesAndValues { get; set; }
But this doesn't work on multiple, identical keys such as "note" and "todo" in the above example since keys have to be unique in a Dictionary.
What is the best collection so that I can not only get single values like this:
string variableValue = "";
if (VariableNamesAndValues.TryGetValue("title", out variableValue))
return variableValue;
else
return "";
but that I can also get multiple values out like this:
//PSEUDO-CODE:
List<string> variableValues = new List<string>();
if (VariableNamesAndValues.TryGetValues("note", out variableValues))
return variableValues;
else
return null;
If your keys and values are strings then use a NameValueCollection. It supports multiple values for a given key.
It's not the most efficient collection in the world. Particularly because it's a non-generic class, uses a lot of virtual method calls, and the GetValues method will allocate arrays for its return values. But unless you require the best performing collection, this is certainly the most convenient collection that does what you ask.
You can make a Dictionary of key: string and value: List of String
Dictionary<string,List<string>>
EDIT 1 & 2:
I've thought of a better solution if you can use .NET 3.0 or higher.
Here's a LINQ example (I typed it without Visual Studio, so I hope it compiles ;)):
string[] lines = File.ReadAllLines("content.txt");
string[] separator = {":: "};
var splitOptions = StringSplitOptions.RemoveEmptyEntries;
var items = from line in lines
let parts = line.Split(separator, splitOptions)
group parts by parts[0] into partGroups
select partGroups;
A short explanation of the example above:
Get all lines from the file in a String array
Define some Split options (to keep the example readable)
For each line in the lines array, split it on the ":: "
Group the results of the split on the first split part (e.g. title, description, note, ...)
Store the grouped items in the items variable
The result of the LINQ query is a IQueryable<IGrouping<string, IEnumberable<string>>>.
Each item in the result has a Key property containing the key of the line (title, description, note, ...).
Each item can be enumerated containing all of values.
You could use a Lookup<TKey, TElement> :
ILookup<string, string> lookup = lines.Select(line => line.Split(new string[] { ":: " })
.ToLookup(arr => arr[0], arr => arr[1]);
IEnumerable<string> notes = lookup["note"];
Note that this collection is read-only
You may use PowerCollections which is an open source project that has a MultiDictionary data structure which solves your problem.
Here is a sample of how to use it.
Note: Jon Skeet suggested it before in his answer to this question.
I'm not a c# expert, but I think Dictionary<string, List<string>>
or some kind of HashMap<string, List<string>> might work.
For example (Java pseudocode):
aKey aValue
aKey anotherValue
if(map.get(aKey) == null)
{
map.put(aKey, new ArrayList(){{add(aValue);}});
}
else
{
map.put(aKey, map.get(aKey).add(anotherValue));
}
or something similar.
(or, the shortest way:
map.put(aKey, map.get(aKey) != null ? map.get(aKey).add(value) : new ArrayList(){{add(value);}});
I have used Dictionary<string, HashSet<string>> for getting multiple values in the past. I would love to know if there is something better though.
Here is how you can emulate getting only one value.
public static bool TryGetValue(this Dictionary<string, HashSet<string>> map, string key, out string result)
{
var set = default(HashSet<string>);
if (map.TryGetValue(key, out set))
{
result = set.FirstOrDefault();
return result == default(string);
}
result = default(string);
return false;
}

Categories