Given a list<StringCollection> how do most efficiently check whether all string are contained in any of the StringCollections?
Example:
using System;
using System.Collections.Specialized;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// Create and initializes a new StringCollection.
StringCollection myCol0 = new StringCollection();
StringCollection myCol1 = new StringCollection();
StringCollection myCol2 = new StringCollection();
StringCollection SearchCol = new StringCollection();
// Add a range of elements from an array to the end of the StringCollection.
String[] myArr0 = new String[] { "RED", "car", "boat" };
myCol0.AddRange( myArr0 );
// Add a range of elements from an array to the end of the StringCollection.
String[] myArr1 = new String[] { "Blue", "Goku", "Nappa" };
myCol1.AddRange( myArr1 );
// Add a range of elements from an array to the end of the StringCollection.
String[] myArr2 = new String[] { "Yellow", "Winter", "Summer" };
myCol2.AddRange( myArr2 );
// Add a range of elements from an array to the end of the StringCollection.
String[] myArr3 = new String[] { "Yellow", "Blue", "RED" };
SearchCol.AddRange( myArr3 );
List<StringCollection> a = new List<StringCollection>();
a.Add(myCol0);
a.Add(myCol1);
a.Add(myCol2);
}
}
In this case I want to know whether the strings in SearchCol is contained within the stringcollections stored in List<StringCollection> a
In this case I just like to know which of the searchCol strings is not included in the List<StringCollection> a
The only way I see this it possible to do so is via a double for loop?
Is there any datastructure that would be more efficient rather than an stringcollection?
Is there any datastructure that would be more efficient rather than
an stringcollection
Efficient in what way? Of course you should normally use a IEnumerable<string>(like a string[] vor List<string>) since StringCollection is not generic.
But you can also use StringCollection, you have to cast each item from object to string:
var allStrings = a.SelectMany(c => c.Cast<string>());
var searchStrings = SearchCol.Cast<string>();
bool allSearchStringsAreContained = searchStrings.All(allStrings.Contains);
as for the "how do most efficiently", this simple approach is efficient, but if you have a large list of strings that you search or huge string lists, you could use a set based approach:
HashSet<string> set = new HashSet<string>(searchStrings);
bool allSearchStringsAreContained = set.IsSubsetOf(allStrings);
Finally, if you want to ignore the case, so treat "RED" and "Red" same:
Approach 1:
bool allSearchStringsAreContained = searchStrings.All(s => allStrings.Contains(s, StringComparer.OrdinalIgnoreCase));
Approach 2:
HashSet<string> set = new HashSet<string>(searchStrings, StringComparer.OrdinalIgnoreCase);
Related
Each instance of some Lists in my program are in an arbitrarily different order (as a result of an unfixed bug in Umbraco CMS Forms), and I need to rearrange them to the correct order. I can't use indices and OrderBy as each time the order is different.
I have been trying to iterate the existing List, then, when it finds the correct String that should be in position [0], using .Add to add it to another, empty List. Then continue through adding each value to the correct index.
I can't figure out a way to do this. I need the logic to basically say "look in this list, if the string equals this value, add it to this other list at position 0, then look for the next string to add at position 1, and so on", so at the end I will have the new List in the correct order.
// List to populate from record in wrong order
var extractedFields = new List<KeyValuePair<string, string>>();
// new list to copy values across in correct order
var newOrderFields = new List<KeyValuePair<string, string>>();
// separate list containing data field captions, used to iterate later
var extractedCaptions = new List<string>();
foreach (var field in record.RecordFields)
{
var extractValue = field.Value.ValuesAsString().NullSafeToString();
var extractType = CGHelper.CleanString(field.Value.Field.FieldType.Name).ToLower();
var extractCaption = field.Value.Field.Caption;
extractedFields.Add(new KeyValuePair<string, string>(extractType,
extractValue));
extractedCaptions.Add(extractCaption);
}
var count = 0;
foreach (var cap in extractedCaptions.ToList())
{
if (cap == "Opportunity ID")
{
extractedCaptions.Remove(cap);
extractedCaptions.Insert(0, cap);
var key = extractedFields[count].Key;
var value = extractedFields[count].Value;
newOrderFields.Add(new KeyValuePair<string, string>(key, value));
}
else if (cap == "Name")
{
// etc. identify string to be put into correct order
So to try and explain further, a user submits a form with the fields in a certain order. When we load that form and pull the record through (from the Umbraco Form), it is in a totally different and arbitrary order (and is in a different order for every single form).Therefore I need to iterate the fields and put them back into the order they were in the original form...
I don't know if I understand the situation correctly. But you can utilize the IComparer<T> interface for custom sorting logic.
using System;
using System.Collections.Generic;
namespace Comparer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var list = new[]{"Foobar", "Baz", "Foo", "Foobar", "Bar", };
Array.Sort(list, new CustomComparer(new[]{"Foo", "Bar", "Baz", "Foobar"}));
list.Dump();
// will dump : Foo,Bar,Baz,Foobar,Foobar
}
}
public class CustomComparer : IComparer<string>
{
private readonly string[] priorityList;
public CustomComparer(string[] priorityList)
{
this.priorityList = priorityList;
}
public int Compare(string x, string y)
{
var xIx = Array.IndexOf(priorityList, x);
var yIx = Array.IndexOf(priorityList, y);
return xIx.CompareTo(yIx);
}
}
}
This will sort the array according to indexes proved in the constructor.
Fiddle
I wrote a small example.
You can see it working here.
The idea is iterating the ordered list and search to every value in other one.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<string> ordered = new List<string>(){ "a", "b", "c", "d"};
List<string> nonOrderedAndMissing = new List<string>(){ "c", "d", "a"};
// here is the join
var newList = ordered.Select(a => nonOrderedAndMissing.Contains(a) ? a : null).Where(d => d != null).ToList();
// checking here
foreach(var a in newList){
Console.WriteLine(a);
}
}
}
I have some code that's main purpose is to combine multiple like lists into one master list to return with the View.
ActivityAuditDetails searchParams = new ActivityAuditDetails();
ActivityAuditDetails finalResults = new ActivityAuditDetails();
List<string> finalChangedColumns = new List<string>();
List<string> finalOldValues = new List<string>();
List<string> finalNewValues = new List<string>();
string finalAuditAction = string.Empty;
List<int> auditKeys = AuditIdentityId.Split(',').Select(int.Parse).ToList();
string url = "/Audit/GetActivityAuditDetails";
try
{
foreach (int auditKey in auditKeys)
{
searchParams.AuditIdentityId = auditKey;
ActivityAuditDetails result = // SOME METHOD THAT RETURNS RESULTS AS IT SHOULD;
finalChangedColumns.Concat(result.ChangedColumns);
finalAuditAction = result.AuditAction;
finalOldValues.Concat(result.OldValues);
finalNewValues.Concat(result.NewValues);
}
finalResults.ChangedColumns = finalChangedColumns;
finalResults.AuditAction = finalAuditAction;
finalResults.OldValues = finalOldValues;
finalResults.NewValues = finalNewValues;
}
catch (Exception e)
{
e.ToLog();
}
return View(finalResults);
I can see that the result object is populated as it should be in the debugger. I thought the Concat method would work to combine the lists, but my final values in the foreach loop never get update\incremented ( the list count remains zero ).
Is there another way to accomplish this, or am I having a morning brain fart? My question was not about the differences, as I was aware of them. I just had a momentary lapse of reason.
You likely want to use AddRange rather than Concat.
The former adds the data directly to the List. The latter concatenates data into a new IEnumerable.
But because you are not assigning the result of Concat to anything (i.e. var g = finalChangedColumns.Concat(result.ChangedColumns);) your Concat calls do effectively nothing.
List<T>.AddRange(IEnumerable<T> collection) (link to info) probably does what you're looking for, right?
Adds the elements of the specified collection to the end of the List.
From documentation:
string[] input = { "Brachiosaurus",
"Amargasaurus",
"Mamenchisaurus" };
List<string> dinosaurs = new List<string>();
dinosaurs.AddRange(input);
//The list now contains all dinosaurs from the input string array
I need to get the index of one array elements in another array using LINQ
The following are my two array:
string[] arr1 = new string[] { "Albany", "Albuquerque", "Anchorage", "Atlantic City",
"Baton Rouge", "Biloxi", "CEDAR SPRINGS", "Chicago", "Columbia", "Columbus" };
string[] arr2 = new string[] { "Albany", "Biloxi" };
Can anybody help me out on the same?
You can use Array.IndexOf:
int[] indicesOf2In1 = arr2.Select(s => Array.IndexOf(arr1, s)).ToArray(); // (0,5)
I've a list with some strings like this:
List<String> data = new List<String>
{
"marine",
"blue",
"SEM",
"seven",
"sensible",
"six"
};
Now I want to compare this list with a string and add the matching items to a new list:
String input = "se";
List<String> newList = new List<String>;
The matching condition is, that the first letters should be the same (case-sensitive). In this case the newList contains:
"seven" and "sensible"
How is the most performant solution?
var newList = data.Where(s => s.StartsWith(input)).ToList();
Let's say I have following code:
List<string> numbers = new List<string> { "1", "2" };
List<string> numbers2 = new List<string> { "1", "2"};
if (numbers.Equals(numbers2))
{
}
Like you can see I have two lists with identical items. Is there a way to check if these two lists are equal by using one method?
SOLUTION:
Use SequenceEqual()
Thanks
Use Enumerable.SequenceEqual, but Sort the lists first.
// if order does not matter
bool theSame = numbers.Except(numbers2).Count() == 0;
// if order is matter
var set = new HashSet<string>(numbers);
set.SymmetricExceptWith(numbers2);
bool theSame = set.Count == 0;