Dictionary, multidimensional or jagged array - c#

I have this string:
string Text = "{1}[56](17)(20)(13)(14)[895](11)(20)[3](8)(12)(3)[19](1)(2)(13)(7)(6)";
and i have to return this:
Array ( [Type] => 1
[Items] => Array ( [56] => Array ( [1] => 17
[2] => 20
[3] => 13
[4] => 14 )
[895] => Array ( [1] => 11
[2] => 20 )
[3] => Array ( [1] => 8
[2] => 12
[3] => 3 )
[19] => Array ( [1] => 1
[2] => 2
[3] => 13
[4] => 7
[5] => 6 )
)
)
How can i make this? I succeded in php but in c# i can't find the solution. I've tried first with dictionary, but i just can't reach it. I just don't know how to make a dictionary with a key with multiple values witch also have multiple values. So far i did this:
var Menu_Matrix = new Dictionary<string, string>();
var Menu_Items = new Dictionary<string, List<string>>();
char[] sep1 = { '{', '}' };
char[] sep2 = { '[', ']' };
char[] sep3 = { '(', ')' };
string[] Menu_Id = new string [10];
string[] Category_Id = new string[20];
Menu_Id = Text.Split(sep1);
Menu_Matrix.Add("Type", Menu_Id[1]);
Category_Id = Menu_Id[2].Split(sep2);
int cat_len = 0;
cat_len = Category_Id.Length;
for (int i = 1; i < cat_len;i++)
{ int pos = 0;
if(Category_Id[i+1].IndexOf('(')!=-1)
pos=i+1;
if(pos>i)
{ var item = new List<string>();
string[] Item_id = new string[20];
Item_id = Category_Id[pos].Split(sep3);
for (int j = 1; j < Item_id.Length;j++ )
if(Item_id[j]!="")
item.Add(Item_id[j]);
Menu_Items.Add(Category_Id[i], item);
}
i = pos;
}
}
return Menu_Items;
and the result is:
[56] => Array ( [1] => 17
[2] => 20
[3] => 13
[4] => 14 )
[895] => Array ( [1] => 11
[2] => 20 )
[3] => Array ( [1] => 8
[2] => 12
[3] => 3 )
[19] => Array ( [1] => 1
[2] => 2
[3] => 13
[4] => 7
[5] => 6 )
Hope you know what i wanna say and help me please! I don't care what i use : dictionary, jagged array or multidimensional array .

I thought a Dictionary<string, Dictionary<string, List<int>>> would be a good structure to store this information in.
The key to the outer Dictionary would be the values of "{#}"
The key to the inner Dictionary would be the values of "[#]"
The values in the List, in the inner Dictionary, would be the values of "(#)", but without the parentheses
To parse out this information, I thought a combinations of Regex.Splits to get the outer and inner keys along with a Regex.Match to get the values of the inner keys was a good approach.
Code Sample:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
string Text = "{1}[56](17)(20)(13)(14)[895](11)(20)[3](8)(12)(3)[19](1)(2)(13)(7)(6){2}[99](1)(2)(3)";
// Split out pairs
// 0: {#}
// 1: [#](#)..(n)
string[] splits = Regex.Split(Text, "({\\d+})").Where(split => !String.IsNullOrEmpty(split)).ToArray();
Dictionary<string, Dictionary<string, List<int>>> items = new Dictionary<string, Dictionary<string, List<int>>>();
for (int i = 0; i < splits.Length; i += 2)
{
// splits[i] is {#} which will make the key for this part of the Dictionary
items.Add(splits[i], new Dictionary<string, List<int>>());
items[splits[i]] = new Dictionary<string, List<int>>();
// Split out sub pairs
// 0: [#]
// 1: (#)..(n)
string[] subSplits = Regex.Split(splits[i + 1], "(\\[\\d+\\])").Where(subSplit => !String.IsNullOrEmpty(subSplit)).ToArray();
for (int j = 0; j < subSplits.Length; j += 2)
{
// subSplits[j] is [#] which will make the key for the inner Dictionary
items[splits[i]].Add(subSplits[j], new List<int>());
// subSplits[j + 1] is all of the (#) for each [#]
// which we'll add to the List of the inner Dictionary
Match m = Regex.Match(subSplits[j + 1], "(\\d+)");
while (m.Success)
{
items[splits[i]][subSplits[j]].Add(Convert.ToInt32(m.Groups[0].ToString()));
m = m.NextMatch();
}
}
}
// Print the keys of the Dictionary, the keys of the inner Dictionary, the values of the inner Dictionary
foreach (string key in items.Keys)
{
Console.WriteLine("Key: {0}", key);
foreach (string subKey in items[key].Keys)
{
Console.WriteLine("\t SubKey: {0}", subKey);
Console.WriteLine("\t\t Value: {0}", String.Join(", ", items[key][subKey]));
}
}
}
}
Results:
Key: {1}
SubKey: [56]
Value: 17, 20, 13, 14
SubKey: [895]
Value: 11, 20
SubKey: [3]
Value: 8, 12, 3
SubKey: [19]
Value: 1, 2, 13, 7, 6
Key: {2}
SubKey: [99]
Value: 1, 2, 3
See working sample here... https://dotnetfiddle.net/Zt5gXc

You could consider something like this:
string text = "{1}[56](17)(20)(13)(14)[895](11)(20)[3](8)(12)(3)[19](1)(2)(13)(7)(6)";
string[] tokens = text.Split(new Char[] { '}', ']', ')' });
char symbol;
int value;
Dictionary<int, Dictionary<int, List<int>>> data = new Dictionary<int, Dictionary<int, List<int>>>();
Dictionary<int, List<int>> items = null;
List<int> leaves = null;
foreach (string token in tokens) {
if (token.Length == 0) break;
symbol = token[0];
value = Int32.Parse(token.Substring(1));
switch (symbol) {
case '{':
items = new Dictionary<int, List<int>>();
data.Add(value, items);
break;
case '[':
leaves = new List<int>();
items.Add(value, leaves);
break;
case '(':
leaves.Add(value);
break;
}
}
foreach (int type in data.Keys)
{
Console.WriteLine("Type => {{{0}}}", type);
Console.WriteLine("\tItems =>");
items = data[type];
foreach (int item in items.Keys)
{
Console.WriteLine("\t\t[{0}] =>", item);
leaves = items[item];
for (int i = 0; i < leaves.Count; i += 1) {
Console.WriteLine("\t\t\t[{0}] => ({1})", i, leaves[i]);
}
}
}
See this working at DotNetFiddle.net
This produces the output:
Type => {1}
Items =>
[56] =>
[0] => (17)
[1] => (20)
[2] => (13)
[3] => (14)
[895] =>
[0] => (11)
[1] => (20)
[3] =>
[0] => (8)
[1] => (12)
[2] => (3)
[19] =>
[0] => (1)
[1] => (2)
[2] => (13)
[3] => (7)
[4] => (6)
Here's a run-down of how it works:
Split all the numbers on the closing mark (curly brace, square bracket, or parenthesis). This creates an array like { "{1", "[56", "(17", ... "(6", "" }.
Create a variable for each level of the data structures that represents the last object at that depth of the hierarchy.
Quit early if we're on the last, blank, token.
Iterate over the split-out tokens and save the opening mark that represents the data structure hierarchy level into symbol and the the numerical value into value.
For each symbol, take the appropriate action.
Huge note: this code strongly expects the input string to be well-formed. If, for example, you passed in the string "{1}(17)" everything would blow up because no intermediate [56] was present to populate the leaves variable with new List<int> that the ( code expects to be instantiated already.

Related

Join keys in key-value pair list with close value c#

I have a list of key-value pairs of <string, int>. I want to merge and construct a new string with the keys that has close values (+3-3) and add each new string to a list.
Here are the keys and values of my list:
Luger: 9
Burger: 9
Le: 21
Pigeon: 21
Burger: 21
Hamburger: 25
Double: 30
Animal: 31
Style: 31
The: 43
Original: 43
Burger: 44
Here's the output that i want to achieve:
Luger Burger
Le Pigeon Burger
Hamburger
Double Animal Style
The Original Burger
To achieve this, firstly i created a list containing this key-value pairs. And iterate through each item and tried to find close values, assign them to new key-value pairs and delete that index. But that doesn't work properly. That's the code so far:
for (int i = 0; i < wordslist.Count; i++)
{
for (int j = 0; j < wordslist.Count; j++)
{
if (wordslist[i].Value <= wordslist[j].Value + 3 && wordslist[i].Value >= wordslist[j].Value - 3)
{
wordslist.Add(
new KeyValuePair<string, int>(wordslist[i].Key + " " + wordslist[j].Key, wordslist[i].Value)
);
wordslist.RemoveAt(j);
}
}
wordslist.RemoveAt(i);
}
this doesn't work and produce repetitive results as below:
Pigeon: 21
Style: 30
Burger: 30
Double Double Animal: 30
Burger Burger: 31
Original Original The The Original Burger Original Burger: 42
Is there any algorithm that can iterate through these items and construct a string by merging the keys that has close values and add each item to a list?
You can simplify this logic:
public IEnumerable<string> GetPlusOrMinus3(Dictionary<string, int> fullList, int checkNumber)
{
return fullList.Where(w => checkNumber <= w.Value + 3
&& checkNumber >= w.Value - 3)
.Select(s => $"{s.Key}: {s.Value}" );
}
The string format isn't perfect for you, but the logic should hold.
And in use you could do something like:
var forOne = GetPlusOrMinus3(values, 1);
var resultString = String.Join(", ", forOne);
Console.WriteLine(resultString);
Which would write out:
one: 1, two: 2, four: 4
And to loop through everything:
foreach(var entryValue in values.Values)
{
Console.WriteLine(String.Join(", ", GetPlusOrMinus3(values, entryValue)));
}
Or to loop through anything without resusing any results:
var matchedNumbers = new List<int>();
foreach(var entryValue in values.Values)
{
var matchResults = values.Where(w => entryValue <= w.Value + 3 && entryValue >= w.Value - 3
&& !matchedNumbers.Contains(w.Value)).ToDictionary(x => x.Key, x => x.Value);
if (matchResults.Any())
{
matchedNumbers.AddRange(matchResults.Select(s => s.Value).ToList());
Console.WriteLine(String.Join(", ",
GetPlusOrMinus3(matchResults, entryValue)));
}
}
Logs:
one: 1, two: 2, four: 4
twelve: 12, 10: 10, eleven: 11
six: 6

Order two dictionaries based on the keys

I've got two dictionaries with the same keys.
The first one contains the count to a specific key and the second one is like a lookup, it contains the real "values" to the specific key.
Here is an example:
1. dict:
Key: Value:
0; 10
1; 17
2; 3
3; 28
4; 8
2. dict:
Key: Value:
0; String1
1; String2
2; String3
3; String4
4; String5
Now I need to order these dictionaries by the value of the 1. dictionary. I know how to order just the first one but i don't have an idea how to do it for the second dictionary.
The expected output is:
1. dict:
Key: Value:
0; 28
1; 17
2; 10
3; 8
4; 3
2. dict:
Key: Value:
0; String4
1; String2
2; String1
3; String5
4; String3
Well, dictionaries (like these)
var dict1 = new Dictionary<int, int>() {
{0, 10},
{1, 17},
{2, 3},
{3, 28},
{4, 8},
};
var dict2 = new Dictionary<int, string>() {
{0, "String 1"},
{1, "String 2"},
{2, "String 3"},
{3, "String 4"},
{4, "String 5"},
};
doesn't have any order. However, we can represent (with a help of Linq) data sorted:
// Just an OrderBy...
var result1 = dict1
.OrderByDescending(pair => pair.Value);
// It may appear, that dict1 doesn't have corresponding value
// that's why we have to introduce "found" variable
var result2 = dict2
.Select(pair => {
bool found = dict1.TryGetValue(pair.Key, out var value);
return new {
pair,
found,
value
};
})
.OrderByDescending(item => item.found)
.ThenByDescending(item => item.value)
.Select(item => item.pair);
Console.WriteLine(string.Join(Environment.NewLine, result1);
Console.WriteLine();
Console.WriteLine(string.Join(Environment.NewLine, result2);
Outcome:
[3, 28]
[1, 17]
[0, 10]
[4, 8]
[2, 3]
[3, String 4]
[1, String 2]
[0, String 1]
[4, String 5]
[2, String 3]
In case you want to enumerate Values only (without Keys) we can add one more Select:
.Select((pair, i) => $"{i + 1}; {pair.Value}");
Like this:
var result1 = dict1
.OrderByDescending(pair => pair.Value)
.Select((pair, i) => $"{i + 1}; {pair.Value}");
var result2 = dict2
.Select(pair => {
bool found = dict1.TryGetValue(pair.Key, out var value);
return new {
pair,
found,
value
};
})
.OrderByDescending(item => item.found)
.ThenByDescending(item => item.value)
.Select(item => item.pair)
.Select((pair, i) => $"{i + 1}; {pair.Value}");
Outcome:
1; 28
2; 17
3; 10
4; 8
5; 3
1; String 4
2; String 2
3; String 1
4; String 5
5; String 3
If key would be same for both the dictionary with same sequence then this would be the design.
Combine two dictionary into one and order them and then generate the sequence number on that.
var dict1 = new Dictionary<int, String>();
dict1.Add(10, "string1");
dict1.Add(17, "string2");
dict1.Add(3, "string3");
dict1.Add(28, "string4");
dict1.Add(8, "string5");
var dict2 = new Dictionary<int, String>();
int i = 0;
foreach (KeyValuePair<int, string> author in dict1.OrderByDescending(key => key.Key))
{
dict2.Add(i, author.Value);
i++;
}
foreach (KeyValuePair<int, string> author in dict2)
{
Console.WriteLine("Key: {0}, Value: {1}", author.Key, author.Value);
}
DEMO

How to remove duplicate rows from nested list?

I have nested list to perform as 2D array:
public List<List<float?>> arrayFloatValue = new List<List<float?>>();
This nested list has 2000 columns in parent and 20000 float values in child array. Now I want to match repeated rows and remove from sub list. Below is sample code.
//Define capacity
int ColumnsCount = 2000;
int RowsCount = 20000;
//Create object
public List<List<float?>> arrayFloatValue = new List<List<float?>>();
//Initiate parent list i.e. 2000
arrayFloatValue = new List<float?>[ColumnsCount].ToList();
//Initiate child list i.e. 20000
for (int i = 0; i < ColumnsCount; i++)
{
arrayFloatValue[i] = new float?[RowsCount].ToList();
}
//Fill dummy data.
for (int x = 0; x < ColumnsCount; x++)
{
for (int y = 0; y < RowsCount; y++)
{
if (y % 50 != 0)
arrayFloatValue[x][y] = x + y; // Assign dummy value
else
arrayFloatValue[x][y] = 0; // Forcefully 0 value added for each 50th row.
}
}
Now I have array like
// [0] [0] [1] [0] [2] [0] ...
// [1] [2] [3] ...
// [2] [3] [4] ...
// [3] [4] [5] ...
// [4] [5] [6] ...
// [5] [6] [7] ...
// [6] [7] [8] ...
// [7] [8] [9] ...
// [8] [9] [10] ...
// [9] [10] [11] ...
// ... ... ...
// [49] [50] [51] ...
// [0] [0] [0] ...
//
// And so on..
//
Now I want to remove repeated values in each column. Here in above example I have 0 value as repeated at each row index like 50th, 100th 150th .... so on. I want to remove these rows.
You can try good old Distinct with a custom IEqualityComparer<T> (we are going to compare lists with SequenceEqual):
public class ListComparer<T> : IEqualityComparer<IEnumerable<T>> {
public bool Equals(IEnumerable<T> x, IEnumerable<T> y) {
return Enumerable.SequenceEqual(x, y);
}
public int GetHashCode(IEnumerable<T> obj) {
return obj == null ? -1 : obj.Count();
}
}
Now Distinct:
List<List<float?>> list = new List<List<float?>>() {
new List<float?>() { 1, 2, 3},
new List<float?>() { 4, 5, 6, 7},
new List<float?>() { 1, 2, 3},
new List<float?>() { null },
new List<float?>() { 1, 2, null },
new List<float?>() { null },
new List<float?>() { 1, 2 },
};
var result = list
.Distinct(new ListComparer<float?>());
string report = string.Join(Environment.NewLine,
result.Select(line => $"{string.Join(", ", line)}"));
Console.Write(report);
Outcome:
1, 2, 3
4, 5, 6, 7
1, 2,
1, 2
If I understand your question, you can use a HashSet to filter your list. But you have to define a IEqualityComparer> that checks the equality of the elements.
I did an example:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MyNamespace
{
public class Program
{
public static void Main()
{
List<List<float>> arrayFloatValue = new List<List<float>>
{
new List<float> {1, 2, 3},
new List<float> {1, 3, 2},
new List<float> {1, 2, 3},
new List<float> {3, 5, 7}
};
var hsArrayFloatValue = new HashSet<List<float>>(arrayFloatValue, new ListComparer());
List<List<float>> filteredArrayFloatValue = hsArrayFloatValue.ToList();
DisplayNestedList(filteredArrayFloatValue);
//output:
//1 2 3
//1 3 2
//3 5 7
}
public static void DisplayNestedList(List<List<float>> nestedList)
{
foreach (List<float> list in nestedList)
{
foreach (float f in list)
Console.Write(f + " ");
Console.WriteLine();
}
Console.ReadLine();
}
}
public class ListComparer : IEqualityComparer<List<float>>
{
public bool Equals(List<float> x, List<float> y)
{
if (x == null && y == null)
return true;
if (x == null || y == null || x.Count != y.Count)
return false;
return !x.Where((t, i) => t != y[i]).Any();
}
public int GetHashCode(List<float> obj)
{
int result = 0;
foreach (float f in obj)
result |= f.GetHashCode();
return result;
}
}
}
Although, I don't recommend you to compare floats. Use decimals instead.

How to go through an array and create a list to count the number of times a number is repeated

friends of the forum.
First of all I apologize for my English
How to go through an array and create a list to count the number of times a number is repeated and sorted by item2 from highest to lowest.
I have the following array:
int[] arrayNumeros= new int[10] {1,2,3,4,5,6,1,1,2,3}
I have the following List:
List<Tuple<int, int>> contadorNumerosTotal = new List<Tuple<int, int>>();
This is my code:
for (int i = 0; i < arrayNumeros.Length; i++)
{
if (contadorNumerosTotal.Any(t => t.Item1 == arrayNumeros[i]))
{
//if the number exists I want item2 to be incremented by 1.
}else{
contadorNumerosTotal.Add(new Tuple<int, int>(arrayNumeros[i], 1));
}
}
for (int i = 0; i < contadorNumerosTotal.Count; i++)
{
System.Diagnostics.Debug.WriteLine(contadorNumerosTotal[i].Item1 +" -> "+ contadorNumerosTotal[i].Item2);
}
As a result it should show:
1 -> 3
3 -> 3
2 -> 2
4 -> 1
5 -> 1
6 -> 1
Thank you very much for your time
The following should produce the desired results:
int[] numbers = new int[] {1,2,3,4,5,6,1,1,2,3};
Dictionary<int, int> numberCount = new Dictionary<int, int>();
int len = numbers.Length;
for(int i = 0; i < len; i++)
{
if (numberCount.ContainsKey(numbers[i]))
{
numberCount[numbers[i]]++;
}
else
{
numberCount[numbers[i]] = 1;
}
}
// Sort by value if necessary. Otherwise loop through numberCount.
var sortednumberCount = numberCount.OrderByDescending(pair => pair.Value);
foreach (var number in sortednumberCount)
{
Console.WriteLine("{0} -> {1}", number.Key, number.Value);
}
Output:
1 -> 3
2 -> 2
3 -> 2
4 -> 1
5 -> 1
6 -> 1
You could use something like this:
List<Tuple<int, int>> contadorNumerosTotal =
arrayNumeros.GroupBy (i => i).Select (ints => new Tuple<int, int> (ints.Key, ints.Count ())).ToList ();
contadorNumerosTotal.Sort ((tuple, tuple1) => tuple1.Item2.CompareTo (tuple.Item2));
This takes the elements, groups arrayNumeros by the value of the numbers and transforms the list, so that it contains the value (this is the key of the group) and the count of the value (this is the count of the group). Lastly it sorts the elements of the list descending from the count (You could sort it ascending by comparing the Item2 of tuple to the Item2 of tuple1 instead of the other way round.
You could print the results like this:
int [] arrayNumeros = new int[10] {1, 2, 3, 4, 5, 6, 1, 1, 2, 3};
List<Tuple<int, int>> contadorNumerosTotal =
arrayNumeros.GroupBy (i => i).Select (ints => new Tuple<int, int> (ints.Key, ints.Count ())).ToList ();
contadorNumerosTotal.Sort ((tuple, tuple1) => tuple1.Item2.CompareTo (tuple.Item2));
foreach (var count in contadorNumerosTotal)
Console.WriteLine ($"{count.Item1} -> {count.Item2}");
Console.ReadLine ();
Which results in the following:
1 -> 3
2 -> 2
3 -> 2
4 -> 1
5 -> 1
6 -> 1
Read more about groupBy here.
int[] arrayNumeros= new int[10] {1,2,3,4,5,6,1,1,2,3};
var result = arrayNumeros
.GroupBy( e => e )
.ToDictionary( e => e.Key, e => e.Count() )
.OrderByDescending( e => e.Value )
.ThenBy( e => e.Key )
.Select( e => Tuple.Create( e.Key, e.Value ) )
.ToList();
.net fiddle sample

Split string array into smaller arrays

I've looked around but can't find anything that has helped me. I have the following issue - I have a string array that contains:
[0] = "2.4 kWh # 105.00 c/kWh"
where [0] is the index of the array. I need to split it by a space, so that I can have several smaller arrays. So it should look like:
[0] will contain 2.4
[1] will contain kWh
[2] will contain #
[3] will contain 105.00
[4] will contain c/mWh
I've tried several solutions but none works. Any assistance would be highly appreciated.
Reference
string s = "2.4 kWh # 105.00 c/kWh";
string[] words = s.Split(new char [] {' '}); // Split string on spaces.
foreach (string word in words)
{
Console.WriteLine(word);
}
Then you can get the console output as
2.4
kWh
#
105.00
c/mWh
We'll use string[] strings = new[] { "2.4 kWh # 105.00 c/kWh", "this is a test" }; as an example of your array.
This is how you can put it all into one array. I've kept it as an IEnumerable<T> to keep that benefit, but feel free to append .ToArray().
public IEnumerable<string> SplitAll(IEnumerable<string> collection)
{
return collection.SelectMany(c => c.Split(' '));
}
Here, this would evaluate to { "2.4", "kWh", "#", "105.00", "c/kWh", "this", "is", "a", "test" }.
Or if I'm misunderstanding you and you actually do want an array of arrays,
public IEnumerable<string[]> SplitAll(IEnumerable<string> collection)
{
return collection.Select(c => c.Split(' '));
}
Here, { { "2.4", "kWh", "#", "105.00", "c/kWh" }, { "this", "is", "a", "test" } }.
Or if I'm totally misunderstanding you and you just want to split the one string, that's even easier, and I've already shown it, but you can use string.Split.
This will give you a two dimensional array (array of string arrays):
var newArr = strArr.Select(s => s.Split(' ').ToArray()).ToArray();
for example:
string[] strArr = new string[] { "2.4 kWh # 105.00 c/kWh", "Hello, world" };
var newArr = strArr.Select(s => s.Split(' ').ToArray()).ToArray();
for (int i = 0; i < newArr.Length; i++)
{
for(int j = 0; j < newArr[i].Length; j++)
Console.WriteLine(newArr[i][j]);
Console.WriteLine();
}
// 2.4
// c/kWh
// #
// 105.00
// kWh
//
// Hello,
// world

Categories

Resources