Multi-dimensional arraylist or list in C#? - c#

Is it possible to create a multidimensional list in C#?
I can create an multidimensional array like so:
string[,] results = new string[20, 2];
But I would like to be able to use some of the features in a list or arraylist like being able to add and delete elements.

You can create a list of lists
public class MultiDimList: List<List<string>> { }
or a Dictionary of key-accessible Lists
public class MultiDimDictList: Dictionary<string, List<int>> { }
MultiDimDictList myDicList = new MultiDimDictList ();
myDicList.Add("ages", new List<int>());
myDicList.Add("Salaries", new List<int>());
myDicList.Add("AccountIds", new List<int>());
Generic versions, to implement suggestion in comment from #user420667
public class MultiDimList<T>: List<List<T>> { }
and for the dictionary,
public class MultiDimDictList<K, T>: Dictionary<K, List<T>> { }
// to use it, in client code
var myDicList = new MultiDimDictList<string, int> ();
myDicList.Add("ages", new List<T>());
myDicList["ages"].Add(23);
myDicList["ages"].Add(32);
myDicList["ages"].Add(18);
myDicList.Add("salaries", new List<T>());
myDicList["salaries"].Add(80000);
myDicList["salaries"].Add(100000);
myDicList.Add("accountIds", new List<T>());
myDicList["accountIds"].Add(321123);
myDicList["accountIds"].Add(342653);
or, even better, ...
public class MultiDimDictList<K, T>: Dictionary<K, List<T>>
{
public void Add(K key, T addObject)
{
if(!ContainsKey(key)) Add(key, new List<T>());
if (!base[key].Contains(addObject)) base[key].Add(addObject);
}
}
// and to use it, in client code
var myDicList = new MultiDimDictList<string, int> ();
myDicList.Add("ages", 23);
myDicList.Add("ages", 32);
myDicList.Add("ages", 18);
myDicList.Add("salaries", 80000);
myDicList.Add("salaries", 110000);
myDicList.Add("accountIds", 321123);
myDicList.Add("accountIds", 342653);
EDIT: to include an Add() method for nested instance:
public class NestedMultiDimDictList<K, K2, T>:
MultiDimDictList<K, MultiDimDictList<K2, T>>:
{
public void Add(K key, K2 key2, T addObject)
{
if(!ContainsKey(key)) Add(key,
new MultiDimDictList<K2, T>());
if (!base[key].Contains(key2))
base[key].Add(key2, addObject);
}
}

you just make a list of lists like so:
List<List<string>> results = new List<List<string>>();
and then it's just a matter of using the functionality you want
results.Add(new List<string>()); //adds a new list to your list of lists
results[0].Add("this is a string"); //adds a string to the first list
results[0][0]; //gets the first string in your first list

Not exactly. But you can create a list of lists:
var ll = new List<List<int>>();
for(int i = 0; i < 10; ++i) {
var l = new List<int>();
ll.Add(l);
}

Depending on your exact requirements, you may do best with a jagged array of sorts with:
List<string>[] results = new { new List<string>(), new List<string>() };
Or you may do well with a list of lists or some other such construct.

If you want to modify this I'd go with either of the following:
List<string[]> results;
-- or --
List<List<string>> results;
depending on your needs...

Related

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
}
}

Pass by reference issue using a delegate inside a loop

I have the following code which creates and returns a Dictionary<int, List<string>>
private static readonly Random rnd = new Random();
private static Dictionary<int, List<string>> GenerateValues(string entityType, int rows)
{
var values = new Dictionary<int, List<string>>();
var baseValues = new List<string> { "99 Hellesdon Road","Home","Norfolk","NR6 5EG","Norwich" };
Action<int> rowLoop = null;
switch (entityType)
{
case "Employer":
rowLoop = (row) =>
{
var employer = new List<string>
{
$"Employer {rnd.Next(10000, 99999)}",
$"{rnd.Next(100000000, 999999999)}",
"TRUE"
};
var rowValue = baseValues;
rowValue.AddRange(employer);
values.Add(row, rowValue);
};
break;
case "AssessmentCentre":
rowLoop = (row) =>
{
var rowValue = baseValues;
rowValue.Add($"Assessment Centre {rnd.Next(10000, 99999)}");
values.Add(row, rowValue);
};
break;
}
for (int i = 1; i <= rows; i++)
{
rowLoop(i);
}
return values;
}
And then to call it with...
var spreadsheetValues = GenerateValues("Employer", 5);
Then intention for the code is to have some base values stored in a List<string>, then depending on what entityType is passed into the method, add some additional values to those base values. Then loop round a certain number of rows to create the Dictionary<int, List<string>>, where int is the row number.
The issue I'm having is that baseValues is being updated during each iteration of my for loop. I didn't expect this when using var rowValue = baseValues;
This is a debug screenshot of the last item in the collection....
I am expecting each List<string> in Dictionary<int, List<string>> to contain 8 items, but instead it is growing with each iteration.
Why is this occurring and how might I correct it?
It seems like you are already on track with the solution to your problem but here is a way to solve it.
Where you write
var rowValue = baseValues;
you are really just making "rowValue" a pointer to "baseValues". To make a copy, you could do something like this:
var rowValue = baseValues.ToList();

algorithm for selecting N random elements from a List<T> in C# [duplicate]

This question already has answers here:
Randomize a List<T>
(28 answers)
Closed 6 years ago.
I need a quick algorithm to select 4 random elements from a generic list. For example, I'd like to get 4 random elements from a List and then based on some calculations if elements found not valid then it should again select next 4 random elements from the list.
You could do it like this
public static class Extensions
{
public static Dictionary<int, T> GetRandomElements<T>(this IList<T> list, int quantity)
{
var result = new Dictionary<int, T>();
if (list == null)
return result;
Random rnd = new Random(DateTime.Now.Millisecond);
for (int i = 0; i < quantity; i++)
{
int idx = rnd.Next(0, list.Count);
result.Add(idx, list[idx]);
}
return result;
}
}
Then use the extension method like this:
List<string> list = new List<string>() { "a", "b", "c", "d", "e", "f", "g", "h" };
Dictionary<int, string> randomElements = list.GetRandomElements(3);
foreach (KeyValuePair<int, string> elem in randomElements)
{
Console.WriteLine($"index in original list: {elem.Key} value: {elem.Value}");
}
something like that:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.Add(5);
int n = 4;
var rand = new Random();
var randomObjects = new List<int>();
for (int i = 0; i<n; i++)
{
var index = rand.Next(list.Count);
randomObjects.Add(list[index]);
}
}
}
You can store indexes in some list to get non-repeated indexes:
List<T> GetRandomElements<T>(List<T> allElements, int randomCount = 4)
{
if (allElements.Count < randomCount)
{
return allElements;
}
List<int> indexes = new List<int>();
// use HashSet if performance is very critical and you need a lot of indexes
//HashSet<int> indexes = new HashSet<int>();
List<T> elements = new List<T>();
Random random = new Random();
while (indexes.Count < randomCount)
{
int index = random.Next(allElements.Count);
if (!indexes.Contains(index))
{
indexes.Add(index);
elements.Add(allElements[index]);
}
}
return elements;
}
Then you can do some calculation and call this method:
void Main(String[] args)
{
do
{
List<int> elements = GetRandomelements(yourElements);
//do some calculations
} while (some condition); // while result is not right
}
Suppose that the length of the List is N. Now suppose that you will put these 4 numbers in another List called out. Then you can loop through the List and the probability of the element you are on being chosen is
(4 - (out.Count)) / (N - currentIndex)
funcion (list)
(
loop i=0 i < 4
index = (int) length(list)*random(0 -> 1)
element[i] = list[index]
return element
)
while(check == false)
(
elements = funcion (list)
Do some calculation which returns check == false /true
)
This is the pseudo code, but i think you should of come up with this yourself.
Hope it helps:)
All the answers up to now have one fundamental flaw; you are asking for an algorithm that will generate a random combination of n elements and this combination, following some logic rules, will be valid or not. If its not, a new combination should be produced. Obviously, this new combination should be one that has never been produced before. All the proposed algorithms do not enforce this. If for example out of 1000000 possible combinations, only one is valid, you might waste a whole lot of resources until that particular unique combination is produced.
So, how to solve this? Well, the answer is simple, create all possible unique solutions, and then simply produce them in a random order. Caveat: I will suppose that the input stream has no repeating elements, if it does, then some combinations will not be unique.
First of all, lets write ourselves a handy immutable stack:
class ImmutableStack<T> : IEnumerable<T>
{
public static readonly ImmutableStack<T> Empty = new ImmutableStack<T>();
private readonly T head;
private readonly ImmutableStack<T> tail;
public int Count { get; }
private ImmutableStack()
{
Count = 0;
}
private ImmutableStack(T head, ImmutableStack<T> tail)
{
this.head = head;
this.tail = tail;
Count = tail.Count + 1;
}
public T Peek()
{
if (this == Empty)
throw new InvalidOperationException("Can not peek a empty stack.");
return head;
}
public ImmutableStack<T> Pop()
{
if (this == Empty)
throw new InvalidOperationException("Can not pop a empty stack.");
return tail;
}
public ImmutableStack<T> Push(T item) => new ImmutableStack<T>(item, this);
public IEnumerator<T> GetEnumerator()
{
var current = this;
while (current != Empty)
{
yield return current.head;
current = current.tail;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
This will make our life easier while producing all combinations by recursion. Next, let's get the signature of our main method right:
public static IEnumerable<IEnumerable<T>> GetAllPossibleCombinationsInRandomOrder<T>(
IEnumerable<T> data, int combinationLength)
Ok, that looks about right. Now let's implement this thing:
var allCombinations = GetAllPossibleCombinations(data, combinationLength).ToArray();
var rnd = new Random();
var producedIndexes = new HashSet<int>();
while (producedIndexes.Count < allCombinations.Length)
{
while (true)
{
var index = rnd.Next(allCombinations.Length);
if (!producedIndexes.Contains(index))
{
producedIndexes.Add(index);
yield return allCombinations[index];
break;
}
}
}
Ok, all we are doing here is producing random indexees, checking we haven't produced it yet (we use a HashSet<int> for this), and returning the combination at that index.
Simple, now we only need to take care of GetAllPossibleCombinations(data, combinationLength).
Thats easy, we'll use recursion. Our bail out condition is when our current combination is the specified length. Another caveat: I'm omitting argument validation throughout the whole code, things like checking for null or if the specified length is not bigger than the input length, etc. should be taken care of.
Just for the fun, I'll be using some minor C#7 syntax here: nested functions.
public static IEnumerable<IEnumerable<T>> GetAllPossibleCombinations<T>(
IEnumerable<T> stream, int length)
{
return getAllCombinations(stream, ImmutableStack<T>.Empty);
IEnumerable<IEnumerable<T>> getAllCombinations<T>(IEnumerable<T> currentData, ImmutableStack<T> combination)
{
if (combination.Count == length)
yield return combination;
foreach (var d in currentData)
{
var newCombination = combination.Push(d);
foreach (var c in getAllCombinations(currentData.Except(new[] { d }), newCombination))
{
yield return c;
}
}
}
}
And there we go, now we can use this:
var data = "abc";
var random = GetAllPossibleCombinationsInRandomOrder(data, 2);
foreach (var r in random)
{
Console.WriteLine(string.Join("", r));
}
And sure enough, the output is:
bc
cb
ab
ac
ba
ca

how to pass multiple objects into a IEnumerable List?

I have this piece of code, which seems to support passing into it many list arguments and it would compare each one against each other one to find a common list among all of the other lists simultaneously.
I cannot figure out how to pass multiple Lists into a single argument thats a IEnmerable.
Say my test code looks like this
List<uint> List1 = new List<uint>();
List<uint> List2 = new List<uint>();
List<uint> List3 = new List<uint>();
List<uint> Commons = FindCommon(List1, List2, List3); //no compile
List<uint> Commons = FindCommon<List<uint>>(List1, List2, List3); //no compile?? why
How do I call this properly?? must I merge them somehow into a IEnumerable?? or must I somehow combine them all into 1 list yet keeping some kind of invisible divider?
static List<T> FindCommon<T>(IEnumerable<List<T>> lists)
{
Dictionary<T, int> map = new Dictionary<T, int>();
int listCount = 0; // number of lists
foreach (IEnumerable<T> list in lists)
{
listCount++;
foreach (T item in list)
{
// Item encountered, increment count
int currCount;
if (!map.TryGetValue(item, out currCount))
currCount = 0;
currCount++;
map[item] = currCount;
}
}
List<T> result= new List<T>();
foreach (KeyValuePair<T,int> kvp in map)
{
// Items whose occurrence count is equal to the number of lists are common to all the lists
if (kvp.Value == listCount)
result.Add(kvp.Key);
}
return result;
}
P.S.> FindCommon is broken somehow it doesn't work properly, probably isn't intended what I thought it should do.. it doesn't check all lists simultaneously together only linear one list at a time with another list which breaks it's purpose, it counts them up.. but it doesn't keep track from which list they came from.
Fixed it like so, this method worked as intended.
public static List<T> FindCommon<T>(params List<T>[] lists)
{
SortedDictionary<T, bool>
current_common = new SortedDictionary<T, bool>(),
common = new SortedDictionary<T, bool>();
foreach (List<T> list in lists)
{
if (current_common.Count == 0)
{
foreach (T item in list)
{
common[item] = true;
}
}
else
{
foreach (T item in list)
{
if (current_common.ContainsKey(item))
{
common[item] = true;
}
}
}
if (common.Count == 0)
{
current_common.Clear();
break;
}
SortedDictionary<T, bool>
swap = current_common;
current_common = common;
common = swap;
common.Clear();
}
return new List<T>(current_common.Keys);
}
You can accomplish this nicely using the params keyword. In your example:
static List<T> FindCommon<T>(params List<T>[] lists)
That would achieve usage:
List<uint> Commons = FindCommon(List1, List2, List3);
You need to Add list1,list2,list3 in another list like ,
List<List<uint>> commonLists=new List<List<uint>>();
commonLists.Add(list1);
commonLists.Add(list2);
commonLists.Add(list3);
List<uint> commons=FindCommon<List<unit>>(commonLists);

Easy initialization of string arrays within a class

If a class contains just string array variables, is there an easy way to initialize them all without having to type the same code over and over?
For example, if I have something like
[Serializable]
public class ReadDiagnosticEntirePointValuesResponse
{
public string[] pointidentifier;
public string[] presentvalue;
public string[] priorityarray;
public string[] alarmstate;
public string[] outofservice;
public string[] correctvalue;
public string[] affect;
public string[] covenable;
public string[] covincrement;
public string[] covtarget;
public string[] covlifetime;
public string[] historyenable;
public string[] historyincrement;
public string[] elapsedactivetime;
public string[] feedbackvalue;
public string[] rawvalue;
...//A lot more
}
and I want to assign values to to them, I want to avoid doing:
ReadDiagnosticEntirePointValuesResponse response = new ReadDiagnosticEntirePointValuesResponse();
response.affect = new string[count];
response.alarmstate = new string[count];
response.correctvalue = new string[count];
response.covenable = new string[count];
response.covincrement = new string[count];
response.covlifetime = new string[count];
response.covtarget = new string[count];
response.elapsedactivetime = new string[count];
response.feedbackvalue = new string[count];
response.historyenable = new string[count];
response.historyincrement = new string[count];
response.outofservice = new string[count];
response.pointidentifier = new string[count];
response.presentvalue = new string[count];
response.priorityarray = new string[count];
response.rawvalue = new string[count];
...
Sure, I could write those initialization in constructor but that still doesn't save me from having to manually initialize them all.
What's a good way to avoid this?
That is a pretty horrible way to manage your data, however, something like the following would work....
foreach(var field in GetType().GetFields()) {
if(!field.IsStatic) field.SetValue(this, new string[count]);
}
However! I strongly suggest you rethink this design. A better mechanism would be:
class DiagnosticPoint // TODO: rename as appropriate
{ // TODO: check these all need to be strings
public string Affect {get;set;}
public string AlarmState {get;set;}
...
public string RawValue {get;set;}
}
and have an array of that as a field:
public class ReadDiagnosticEntirePointValuesResponse
{
DiagnosticPoint[] points;
...
then simply init the array:
points = new DiagnosticPoint[count];
and init each:
for(int i = 0 ; i < count ; i++) points[i] = new DiagnosticPoint();
and access via:
var alarm = points[index].AlarmState;
(etc)
You can use Reflection to do this:
public ReadDiagnosticEntirePointValuesResponse()
{
GetType().GetFields(BindingFlags.Instance | BindingFlags.Public)
.ToList()
.ForEach(field => field.SetValue(this, new string[count]));
}
At least once you have to initialize them manually. if C'tor doesn't suit you, initialize in a new method.
You might want to look at reflection for that... Reading the class' proprties in a loop
This sounds like an awful class definition. Perhaps using an enum might be better.
If you could start with this:
public enum ReadDiagnostic
{
pointidentifier,
presentvalue,
priorityarray,
alarmstate,
outofservice,
correctvalue,
affect,
covenable,
covincrement,
covtarget,
covlifetime,
historyenable,
historyincrement,
elapsedactivetime,
feedbackvalue,
rawvalue,
}
You could then create a Dictionary<ReadDiagnostic, string[]> to hold your values that you were storing in your class.
You could even use LINQ to create your dictionary in one line of code:
var readDiagnosticEntirePointValues =
typeof(ReadDiagnostic)
.GetEnumValues()
.Cast<ReadDiagnostic>()
.ToDictionary(x => x, x => new string[count]);
This approach is still strongly-typed, but much easier to maintain than your current approach.
You could use the following:
response.affect = response.alarmstate = response... = new string[count];
However, using this will still have you initialize them manually. It's just a shortcut.
As others may already have suggested, using Collection Classes will make it a lot easier. I would recommend a Dictionary. Here is how you could implement it:
enum Foo { Affect, AlarmState, CorrectValue, ... }
public void InitializeArrays(int count)
{
Dictionary<Foo, string[]> response = new Dictionary<Foo, string[]>();
// easy initialization of string arrays
foreach (Foo foo in Enum.GetValues(typeof(Foo)))
{
response.Add(foo, new string[count]);
}
// use this to access the string arrays
response[Foo.Affect][0] = "test";
if (response[Foo.CorrectValue].Length > 0) { ... }
}
Alternatively, you could also achieve the same by using a Multidimensional Array.
// initialize it like this
string[,] response = new string[Enum.GetValues(typeof(Foo)).Length, count];
// access it like this
response[(int)Foo.Affect, 0] = "test";
You can use the array list to avoid of declaring the size.

Categories