How to replace value in string array - c#

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());

Related

Get last duplicate element in a list

I have a list contains duplicate items.
List<string> filterList = new List<string>()
{
"postpone", "access", "success", "postpone", "success"
};
I get the output which is postpone, access, success by using
List<string> filter = filterList.Distinct().ToList();
string a = string.Join(",", filter.Select(a => a).ToArray());
Console.WriteLine(a);
I had saw other example, they can use groupby to get the latest element since they have other item like ID etc. Now I only have the string, how can I get the latest item in the list which is access, postpone, success? Any suggestion?
One way to do this would be use the Index of the item in original collection along with GroupBy. For example,
var lastDistinct = filterList.Select((x,index)=> new {Value=x,Index=index})
.GroupBy(x=>x.Value)
.Select(x=> x.Last())
.OrderBy(x=>x.Index)
.Select(x=>x.Value);
var result = string.Join(",",lastDistinct);
Output
access,postpone,success
An OrderedDictionary does this. All you have to do is add your items to it with a logic of "if it's in the dictionary, remove it. add it". OrderedDictionary preserves the order of adding so by removing an earlier added one and re-adding it it jumps to the end of the dictionary
var d = new OrderedDictionary();
filterList.ForEach(x => { if(d.Contains(x)) d.Remove(x); d[x] = null; });
Your d.Keys is now a list of strings
access
postpone
success
OrderedDictionary is in the Collections.Specialized namespace
If you wanted the keys as a CSV, you can use Cast to turn them from object to string
var s = string.Join(",", d.Keys.Cast<string>());
Your input list is only of type string, so using groupBy doesn't really add anything. If you consider your code, your first line gives you the distinct list, you only lose the distinct items because you did a string.join on line 2. All you need to do is add a line before you join:
List<string> filter = filterList.Distinct().ToList();
string last = filter.LastOrDefault();
string a = string.Join(",", filter.Select(a => a).ToArray());
Console.WriteLine(a);
I suppose you could make your code more terse because you need neither .Select(a => a) nor .ToArray() in your call to string.Join.
GroupBy would be used if you had a list of class/struct/record/tuple items, where you might want to group by a specific key (or keys) rather than using Distinct() on the whole thing. GroupBy is very useful and you should learn that, and also the ToDictionary and ToLookup LINQ helper functionality.
So why shouldn't you return the first occurrence of "postpone"? Because later in the sequence you see the same word "postpone" again. Why would you return the first occurrence of "access"? Because later in the sequence you don't see this word anymore.
So: return a word if the rest of the sequence does not have this word.
This would be easy in LINQ, with recursion, but it is not very efficient: for every word you would have to check the rest of the sequence to see if the word is in the rest.
It would be way more efficient to remember the highest index on which you found a word.
As an extension method. If you are not familiar with extension methods, see extension methods demystified.
private static IEnumerable<T> FindLastOccurences<T>(this IEnumerable<T> source)
{
return FindLastOccurrences<T>(source, null);
}
private static IEnumerable<T> FindLastOccurences<T>(this IEnumerable<T> source,
IEqualityComparer<T> comparer)
{
// TODO: check source not null
if (comparer == null) comparer = EqualityComparer<T>.Default;
Dictionary<T, int> dictionary = new Dictionary<T, int>(comparer);
int index = 0;
foreach (T item in source)
{
// did we already see this T? = is this in the dictionary
if (dictionary.TryGetValue(item, out int highestIndex))
{
// we already saw it at index highestIndex.
dictionary[item] = index;
}
else
{
// it is not in the dictionary, we never saw this item.
dictionary.Add(item, index);
}
++index;
}
// return the keys after sorting by value (which contains the highest index)
return dictionay.OrderBy(keyValuePair => keyValuePair.Value)
.Select(keyValuePair => keyValuePair.Key);
}
So for every item in the source sequence, we check if it is in the dictionary. If not, we add the item as key to the dictionary. The value is the index.
If it is already in the dictionary, then the value was the highest index of where we found this item before. Apparently the current index is higher, so we replace the value in the dictionary.
Finally we order the key value pairs in the dictionary by ascending value, and return only the keys.

combining empty/null arrays

I have a page that can pass anywhere from 1 array to 3 arrays.
My current code works but only if each array is populated with items.
[HttpPost, ValidateInput(false)]
public ActionResult AddCampaign(string campaignName, string editor1, Int32[]
productImages, Int32[] lifestyleImages, Int32[] logoImages)
{
// Add image list to CampaignImages table
// Combine image array list into a single array
var imageList = productImages.Concat(lifestyleImages).Concat(logoImages).ToArray();
return RedirectToAction("AddCampaign", "Admin");
}
Each array is the exact same it will only hold an ID of an image. This will work as long as all 3 arrays have something in them. But if one is null it errors out.
What I need is a single array that is a combination of all 3 arrays, productImages, lifestyleImages, logoImages.
Not sure what I am missing.
Well you're missing the fact that Concat will throw an exception if you pass it a null reference... but it's easy enough to fix. Either write an extension method like this:
public static IEnumerable<T> NullToEmpty<T>(this IEnumerable<T> src)
{
return src ?? Enumerable.Empty<T>();
}
And call it as:
var imageList = productImages.NullToEmpty()
.Concat(lifestyleImages.NullToEmpty())
.Concat(logoImages.NullToEmpty())
.ToArray();
... or just use the null-coalescing operator directly:
var empty = Enumerable.Empty<int>();
var imageList = (productImages ?? empty).Concat(lifeStyleImages ?? empty)
.Concat(logoImages ?? empty)
.ToArray();

get list item by id

I have a list:
List<string> theList = new List<string>;
There are a few elements in the List. And now I want to get an item by the index. e.g. I want to get element number 4. How can I do it?
Just use the indexer
string item = theList[3];
Note that indexes in C# are 0 based. So if you want the 4th element in the list you need to use index 3. If you want the 5th element you would use index 4. It's unclear from your question which you intended
The indexer is a common feature on .Net collection types. For lists it's generally index based, for maps it's key based. The documentation for the type in question will tell you which and if it's available. The indexer member will be listed though as the property named Item
http://msdn.microsoft.com/en-us/library/0ebtbkkc.aspx
To get 4th item, you can use indexer:
string item = theList[3];
if you prefer to use methods, then you can use ElementAt or (ElementAtOrDefault):
string item = theList.ElementAt(3);
You can use the Indexer to get the Item at selected index
string item = theList[3];
Use the indexer:
string the4th = theList[3];
Note that this throws an exception if the list has only 3 items or less since the index is always zero-based. You might want to use Enumerable.ElementAtOrDefault then:
string the4th = theList.ElementAtOrDefault(3);
if(the4th != null)
{
// ...
}
ElementAtOrDefault returns the element at the specified index if index < list.Count and default(T) if index >= theList.Count. So for reference types(like String) it returns null and for value types their default value(e.g. 0 for int).
For collection types which implement IList<T>(arrays or lists) it uses the indexer to get the element, for other types it uses a foreach loop and a counter variable.
So you could also use the Count property to check if the list contains enough items for the index:
string the4th = null;
if(index < theList.Count)
{
the4th = theList[index];
}
use the Indexer Syntax:
var fourthItem = theList[3];
this should do it, access via array index.
theList[3]
its 3 as index's start at 0.
You can use the Indexer to get the Item at selected index
string item = theList[3];
Or if u want to get the id (if accessing from database) define a class e.g.
public class Person
{
public int PId;
public string PName;
}
and access as follow
List<Person> theList = new List<Person>();
Person p1 = new Person();
int id = theList[3].PId

Putting a field to the next empty array index

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.

Would this LINQ statement ever return null?

Given the following C# code:
List<string> source = new List<string>();
IEnumerable<string> values = from value in source select value;
Will values ever be null or will it always return an empty sequence?
Yes it CAN return null if you have an extension method defined in your code somewhere like the following:
public static IEnumerable<string> Select(this List<string> list, Func<string, string> action)
{
return null;
}
Otherwise no; it will return an empty sequence.
The values sequence itself will never be null. If source is empty then values will be an empty sequence containing no items.
(And, of course, it's possible that one or more of the string items in the sequence might be null.)
Linq returns empty sequences
If you want to test if the sequence is empty use the .Any() method

Categories