LINQ dictionary to jagged array? - c#

There is a method that returns 2D array, this method querying a dictionary from LINQ query and trying to store keys and values in 2D array.
But I am not able to do that
public string[][] GetRecordFields(string selectedRecord)
{
var recordFields = (from record in _recordMasterList
where record.Item1 == selectedRecord
select new
{
record.Item2.Keys,
record.Item2.Values
}).ToArray();
return recordFields;
}
But its failed, is there any way?
EDIT:
Type of _recordMasterList
List<Tuple<string, Dictionary<string, string>>> _recordMasterList;

Create a string array instead of an object in the query, then the ToArray will return an array of arrays:
public string[][] GetRecordFields(string selectedRecord) {
return (
from record in _recordMasterList
where record.Item1 == selectedRecord
select new string[] {
record.Item2.Keys,
record.Item2.Values
}
).ToArray();
}

In your select you need to create a string array (new []). In your example you were creating a new anonymous type.
public string[][] GetRecordFields(string selectedRecord)
{
string[][] recordFields = (from record in _recordMasterList
where record.Key == selectedRecord
select new []
{
record.Key,
record.Value
}).ToArray();
return recordFields;
}
(I've changed the code slightly to deal with a _recordMasterList of type Dictionary<string, string>. Also, in code like this I find it clearer to declare my variable type explicitly, rather than relying on implicit typing. That said, with arrays I prefer to use implicit array typing - new [] rather than new string[].)

Not a one liner LINQ magic but here it is:
/// <summary>
/// Converts dictionary to 2d string array
/// </summary>
/// <param name="Dictionary">Dictionary to be converted</param>
/// <returns>2D string Array</returns>
private string[,] ConvertDictionaryTo2dStringArray(Dictionary<string, string> Dictionary)
{
string[,] stringArray2d = new string[2, Dictionary.Count];
int i = 0;
foreach (KeyValuePair<string, string> item in Dictionary)
{
stringArray2d[0, i] = item.Key;
stringArray2d[1, i] = item.Value;
i++;
}
return stringArray2d;
}

A more generic version with reversed dimensions:
private object[,] Dictionary2Array(Dictionary<object, object> dic)
{
object[,] arr = new object[dic.Count, 2];
int i = 0;
foreach (KeyValuePair<object, object> item in dic)
{
arr[i, 0] = item.Key;
arr[i, 1] = item.Value;
i++;
}
return arr;
}

Your question is still a little bit confussing. Is this the behaviour you are looking for?
(I know that this answer could be optimised a lot, but it seams the easiest way to figue out what you want.)
public string[,] GetRecordFields(string selectedRecord)
{
//List<Tuple<string, Dictionary<string, string>>> _recordMasterList;
List<Dictionary<string, string>> selectedRecords
= (from record in _recordMasterList
where record.Item1 == selectedRecord
select record.Item2)
.ToList();
int totalNumberOfRecords = 0;
foreach(Dictionary<string, string> d in selectedRecords)
{
totalNumberOfRecords += d.Count();
}
string[,] result = new string[2, totalNumberOfRecords];
int i = 0;
foreach(Dictionary<string, string> d in selectedRecords)
{
foreach(KeyValuePair<string, string> kvp in d)
{
result[0,i] = kvp.Key;
result[1,i] = kvp.Value;
ii++;
}
}
return result;
}

Related

How to print the duplicates value while converting from Dictionary to List in c#

I am trying to converting from dictionary to list while converting I am getting the output
I/p-
dic.Add("Demo1",2);
dic.Add("Demo2",1);
dic.Add("Demo3",1);
dic.Add("Demo4",2);
O/p-
Demo1
Demo2
Demo3
Demo4
But I need Demo1 and Demo4 two times because their quantity are 2. So How can I achieve that??
Below is the code
public IList<string> DictionaryToList(IDictionary<string,int> dictionary)
{
IDictionary<string, int> dic = new Dictionary<string, int>();
IList<string> lst = new List<string>();
dic.Add("Demo1",2);
dic.Add("Demo2",1);
dic.Add("Demo3",1);
dic.Add("Demo4",2);
foreach (var item in dic)
{
if (!lst.Contains(item.Key))
{
lst.Add(item.Key);
}
}
return lst;
}
}
class Program
{
static void Main(string[] args)
{
var conversion = new Conversion();
var list = new List<string> { "Demo1","Demo2","Demo3","Demo4","Demo1","Demo4"};
var dictionary = conversion.ListToDictionary(list);
foreach (var item in dictionary)
{
Console.WriteLine($"{item.Key}, {item.Value}");
}
var convertedList = conversion.DictionaryToList(dictionary);
foreach (var item in convertedList)
{
Console.WriteLine($"{item}");
}
Console.ReadLine();
}
Thanks in advance.
You can use LINQ's SelectMany and Enumerable.Repeat:
IList<string> list = dictionary
.SelectMany(kv => Enumerable.Repeat(kv.Key, kv.Value))
.ToList();
Here is also the opposite way to build your dictionary from the list:
var list = new List<string> { "Demo1", "Demo2", "Demo3", "Demo4", "Demo1", "Demo4" };
var dictionary = list.GroupBy(s => s).ToDictionary(g => g.Key, g => g.Count());
IList<string> list2 = dictionary
.SelectMany(kv => Enumerable.Repeat(kv.Key, kv.Value))
.ToList();
So at the end list2 contains the same strings as list but in a different order.
Your dictionary consists of a key (string) and a value (int). After checking
if (!list.Contains(item.Key)) just add another loop which goes from 0 to the actual value from your dictionary-item and adds the new item n-times.
for (int i = 0; i < item.Value; i++) // Demo1 and Demo4 runs 2x, Demo2 and Demo3 1x
lst.Add(item.Key);
Do you want something like this?
Dictionary<string, int> dic = new Dictionary<string, int>();
List<string> lst = new List<string>();
dic.Add("Demo1", 2);
dic.Add("Demo2", 1);
dic.Add("Demo3", 1);
dic.Add("Demo4", 2);
foreach (var item in dic)
{
for (int i = 0; i < item.Value; i++)
{
lst.Add(item.Key);
}
}

how to swap keys into values and values into key in a dictionary

guys i want to swap the keys and values in dictionary
my dictionary loook like this
public static void Main(string[] args)
{
Dictionary<int,int> dic = new Dictionary<int,int>{{1,10}, {2, 20}, {3, 30}};
}
now iam printing the values form dictionary
foreach (KeyValuePair<int, int> kvp in dic)
{
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
Console.ReadKey();
}
in display i got this
Key = 1, Value = 10
Key = 2, Value = 20
Key = 3, Value = 30
i want to swap values between key and value.. after swapping the answer should be like this
Key = 10, Value = 1
Key = 20, Value = 2
Key = 30, Value = 3
i did lambda expression it changed but i need some other method to do..
Supposing the values are unique, this can work:
var dic = new Dictionary<int,int>{{1,10}, {2, 20}, {3, 30}};
var dic2 = dic.ToDictionary(x => x.Value, x=> x.Key);
It won't actually swap the sides, you will get a new dictionary.
Here is an extension so you can do:
Dictionary<int, int> newDic = oldDic.SwapKeysAndValues();
/// <summary>
/// Take a dictionary and make the values the keys and the keys the values
/// </summary>
/// <typeparam name="K">The original dictionary key type</typeparam>
/// <typeparam name="V">The original value type</typeparam>
/// <param value="dictionary<K, V>"></param>
/// <returns>Dictionary<V, K></returns>
public static Dictionary<V, K> SwapKeysAndValues<K, V>(this Dictionary<K, V> original)
{
Dictionary<V, K> result = new Dictionary<V, K>();
foreach (V value in original.Values.Distinct())
{
result.Add(value, original.First(x => x.Value.Equals(value)).Key);
}
// optional
//if(original.Count > result.Count)
//{
// throw new Exception("Duplicate value ignored ");
//}
return result;
}
I ran speed tests and found creating a new dictionary without specifying the capacity ran slower if there are more than a handful of items. In fact, at 1,000 items it was around 30% slower*. Also if the key and value are the same types, you might also want the same IEqualityComparer to be used in the opposite direction. Finally, if you have a duplicate value, an error will be thrown with the Linq version.
The version here is basically the same as the Linq version with the additions of using the same IEqualityComparer if possible, setting the initial capacity, and preventing potential duplicate errors:
var dic = new Dictionary<int, int>() { { 1, 10 }, { 2, 20 }, { 3, 30 } };
var dic2 = dic.ToDictionarySwapped();
Console.WriteLine(String.Join(",", dic.Select(i => i.Key + ":" + i.Value)));
Console.WriteLine(String.Join(",", dic2.Select(i => i.Key + ":" + i.Value)));
public static Dictionary<V, K> ToDictionarySwapped<K, V>(this Dictionary<K, V> original, bool useSameComparerIfPossible = true)
{
IEqualityComparer<V> comparer = null;
if (useSameComparerIfPossible && typeof(K) == typeof(V)) comparer = (IEqualityComparer<V>)original.Comparer;
var swapped = new Dictionary<V, K>(capacity: original.Count, comparer: comparer);
foreach (var item in original) swapped[item.Value] = item.Key;
return swapped;
}
the test I ran was a loop swapping a dictionary containing 1000 items, 1000 times. The test was repeated with both the capacity being set and the capacity not being set. My average time was around 65ms when the capacity was set, and around 95ms when it was not set. The test was run after being compiled for Release mode.
I think you will understand the below code:
namespace Swap
{
public class Class1
{
public SortedDictionary<string, string> names;
public void BeforeSwaping()
{
Console.WriteLine("Before Swapping: ");
Console.WriteLine();
names = new SortedDictionary<string, string>();
names.Add("Sonoo", "srinath");
names.Add("Perer", "mahesh");
names.Add("James", "ramesh");
names.Add("Ratan", "badri");
names.Add("Irfan", "suresh");
names.Add("sravan", "current");
foreach (KeyValuePair<string, string> item in names)
{
Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}
Console.WriteLine();
}
public void AfterSwaping()
{
Console.WriteLine("After Swapping: ");
Console.WriteLine();
var key = names.Keys;
var val = names.Values;
string[] arrayKey = new string[key.Count];
string[] arrayVal = new string[val.Count];
int i = 0;
foreach (string s in key)
{
arrayKey[i++] = s;
}
int j = 0;
foreach (string s in val)
{
arrayVal[j++] = s;
}
names.Clear();
//Console.WriteLine(arrayVal[0] + " " + arrayKey[0]);
for (int k = 0; k < (arrayKey.Length + arrayVal.Length) / 2; k++)
{
names.Add(arrayVal[k], arrayKey[k]);
}
foreach (KeyValuePair<string, string> s in names)
{
Console.WriteLine("key:"+s.Key + ", "+"value:" + s.Value);
}
}
public static void Main(string[] args)
{
Class1 c = new Class1();
c.BeforeSwaping();
c.AfterSwaping();
Console.ReadKey();
}
}
}

How to reverse the index in array of dictionaries?

My array dictionary key value pairs are similar to this
[0]
key : x
value : 1
[1]
key : y
value : 2
[2]
key : z
value : 3
But I need to reverse the index of the dictionary. I need to convert the above dictionary to this :
[0]
key : z
value : 3
[1]
key : y
value : 2
[2]
key : x
value : 1
I tried Reverse() function. But it didn't work. I don't know how to achieve this. Can anyone help me with this ?
How can I achieve this ?
You shouldn't assume dictionaries are ordered. They aren't.
If you want to have an array that is ordered, you should use a SortedDictionary. You can also reverse the order in there if you want to. You should use a custom comparer for that (altered from here):
class DescendedStringComparer : IComparer<string>
{
public int Compare(string x, string y)
{
int ascendingResult = Comparer<string>.Default.Compare(x, y);
// turn the result around
return 0 - ascendingResult;
}
}
//
SortedDictionary<string, string> test
= new SortedDictionary<string, string>(new DescendedDateComparer());
You can iterate over it with foreach for example. The results will be ordered descending.
the function Enumerable.Reverse() returns an IEnumerable not an array. Did you forget to make the reversed sequence an array? The following worked for me:
class Program
{
static void Main(string[] args)
{
var dict = new Dictionary<string, int>();
dict.Add("x", 1);
dict.Add("y", 2);
dict.Add("z", 3);
var reversed = dict.ToArray().Reverse();
var reversedArray = reversed.ToArray();
Console.ReadKey();
}
}
I tried reverse method, it worked. Please see below images. I used VS 2013, .Net 4.5
Output generated
You should use SortedDictionary and pass a key on construction
public sealed class CompareReverse<T> : IComparer<T>
{
private readonly IComparer<T> original;
public CompareReverse(IComparer<T> original)
{
this.original = original;
}
public int Compare(T left, T right)
{
return original.Compare(right, left);
}
}
and in your main call
var mydictionary = new SortedDictionary<int, string>(
new CompareReverse<int>(Comparer<int>.Default));
for eg:-
var mydictionary = new SortedDictionary<int, string>(
new CompareReverse<int>(Comparer<int>.Default));
dictionary.add(1, "1");
dictionary.add(2, "2");
dictionary.add(3, "3");
dictionary.add(4, "4");
SortedDictionary sorts by key, not by value.
Here's a clean way to reverse the order of values in a Dictionary:
List<KeyValuePair<string, string>> srcList = aDictionary.ToList();
srcList.Sort(
delegate(KeyValuePair<string, string> firstPair,
KeyValuePair<string, string> nextPair)
{
return firstPair.Value.CompareTo(nextPair.Value);
}
);
Dictionary<string, string> outputDictionary = new Dictionary<string, string>();
int listCount = srcList.Count;
for(int i = 0; i < listCount; i++) {
int valueIndex = i + 1;
outputDictionary.Add(srcList[i].Key, srcList[valueIndex]);
}
If what you want as output is a List of KeyValuePairs rather than a Dictionary, you can replace the final 6 lines of code in my example with this:
List<KeyValuePair<string, string>> destList = new List<KeyValuePair<string, string>>();
int listCount = srcList.Count;
for(int i = 0; i < listCount; i++) {
int valueIndex = i + 1;
destList.Add(new KeyValuePair<string, string>(srcList[i].Key, srcList[valueIndex]));
}
You can do this :
for (var i = dictionary.Count - 1; i >= 0; i--)
dictionary.Values.ElementAt(i), dictionary.Keys.ElementAt(i);
EDIT : Go here -> how to iterate a dictionary<string,string> in reverse order(from last to first) in C#?

Get duplicate values from dictionary

I have dictionary and I need get duplicate values.
For example:
Dictionary<int, List<string>> dictionary = new Dictionary<int, List<string>>();
List<string> list1 = new List<string> { "John", "Smith" };
List<string> list2 = new List<string> { "John", "Smith" };
List<string> list3 = new List<string> { "Mike", "Johnson" };
dictionary.Add(1, list1);
dictionary.Add(2, list2);
dictionary.Add(3, list3);
I need find all duplicate from dictionary and return max keys(collection of key) of each duplicate values. From my test dictionary I need return list with only one key = 2
Maybe I chose the wrong data structure. I would like to receive optimal algorithm
With your current structure, you're in a bit of trouble because you don't necessarily have an easy way to compare two List<string> to see if they are equal.
One way to work around this is to create a custom List<string> comparer that implements IEqualityComparer<List<string>>. However, since you have a list of strings, we also need to reorder both to ensure that we are comparing each value in the correct order. This affects the cost of your algorithm. On the other hand, if you are happy with the order of the values inside of the lists, that works just fine as well and you can avoid that cost.
public class StringListComparer : IEqualityComparer<List<string>>
{
public bool Equals(List<string> x, List<string> y)
{
return CompareLists(x, y);
}
public int GetHashCode(List<string> obj)
{
return base.GetHashCode();
}
private static bool CompareLists(List<string> x, List<string> y)
{
if (x.Count != y.Count)
return false;
// we HAVE to ensure that lists are in same order
// for a proper comparison
x = x.OrderBy(v => v).ToList();
y = y.OrderBy(v => v).ToList();
for (var i = 0; i < x.Count(); i++)
{
if (x[i] != y[i])
return false;
}
return true;
}
}
Once we have our comparer, we can use it to pull out keys from subsequent duplicates, leaving the first key (per your requirement).
public List<int> GetDuplicateKeys(Dictionary<int, List<string>> dictionary)
{
return dictionary
.OrderBy (x => x.Key)
.GroupBy(x => x.Value, new StringListComparer())
.Where (x => x.Count () > 1)
.Aggregate (
new List<int>(),
(destination, dict) =>
{
var first = dict.FirstOrDefault();
foreach (var kvp in dict)
{
if (!kvp.Equals(first))
destination.Add(kvp.Key);
}
return destination;
}
).ToList();
}
The following test outputs keys 2 and 4.
Dictionary<int, List<string>> dictionary = new Dictionary<int, List<string>>();
dictionary.Add(1, new List<string> { "John", "Smith" });
dictionary.Add(2, new List<string> { "John", "Smith" });
dictionary.Add(3, new List<string> { "Mike", "Johnson"});
dictionary.Add(4, new List<string> { "John", "Smith" });
var result = GetDuplicateKeys(dictionary);
You could create a list of KeyValuePair<int, List<string>>, that contains the ordered lists, with the outer list sorted. Then you could find duplicates very quickly. You'd need a list comparer that can compare ordered lists.
class MyListComparer: Comparer<List<string>>
{
public override int Compare(List<string> x, List<string> y)
{
for (var ix = 0; ix < x.Count && ix < y.Count; ++ix)
{
var rslt = x[ix].CompareTo(y[ix]);
if (rslt != 0)
{
return rslt;
}
}
// exhausted one of the lists.
// Compare the lengths.
return x.Count.CompareTo(y.Count);
}
}
var comparer = new MyListComparer();
var sortedList = dictionary.Select(kvp =>
new KeyValuePair<int, List<string>>(kvp.Key, kvp.Value.OrderBy(v => v))
.OrderBy(kvp => kvp.Value, comparer)
.ThenBy(kvp => kvp.Key);
Note the ThenBy, which ensures that if two lists are equal, the one with the smaller key will appear first. This is necessary because, although OrderBy does a stable sort, there's no guarantee that enumerating the dictionary returned items in order by key.
// the lists are now sorted by value. So `"Smith, John"` will appear before `"Smith, William"`.
// We can go through the list sequentially to output duplicates.
var previousList = new List<string>();
foreach (var kvp in sortedList)
{
if (kvp.Value.SequenceEqual(previousList))
{
// this list is a duplicate
// Lookup the list using the key.
var dup = dictionary[kvp.Key];
// Do whatever you need to do with the dup
}
else
{
previousList = kvp.Value;
}
}
This sorts each list only once. It does use more memory, because it duplicates the dictionary in that list of KeyValuePair<int, List<string>>, but for larger data sets it should be much faster than sorting each list multiple times and comparing it against every other list.
Caveats: The code above assumes that none of the lists are null, and none of them are empty. If a list in the dictionary can be null or empty, then you'll have to add some special case code. But the general approach would be the same.

How to convert a String[] to an IDictionary<String, String>?

How to convert a String[] to an IDictionary<String, String>?
The values at the indices 0,2,4,... shall be keys, and consequently values at the indices 1,3,5,... shall be values.
Example:
new[] { "^BI", "connectORCL", "^CR", "connectCR" }
=>
new Dictionary<String, String> {{"^BI", "connectORCL"}, {"^CR", "connectCR"}};
I'd recommend a good old for loop for clarity. But if you insist on a LINQ query, this should work:
var dictionary = Enumerable.Range(0, array.Length/2)
.ToDictionary(i => array[2*i], i => array[2*i+1])
Dictionary<string,string> ArrayToDict(string[] arr)
{
if(arr.Length%2!=0)
throw new ArgumentException("Array doesn't contain an even number of entries");
Dictionary<string,string> dict=new Dictionary<string,string>();
for(int i=0;i<arr.Length/2;i++)
{
string key=arr[2*i];
string value=arr[2*i+1];
dict.Add(key,value);
}
return dict;
}
There's really no easy way to do this in LINQ (And even if there were, it's certainly not going to be clear as to the intent). It's easily accomplished by a simple loop though:
// This code assumes you can guarantee your array to always have an even number
// of elements.
var array = new[] { "^BI", "connectORCL", "^CR", "connectCR" };
var dict = new Dictionary<string, string>();
for(int i=0; i < array.Length; i+=2)
{
dict.Add(array[i], array[i+1]);
}
Something like this maybe:
string[] keyValues = new string[20];
Dictionary<string, string> dict = new Dictionary<string, string>();
for (int i = 0; i < keyValues.Length; i+=2)
{
dict.Add(keyValues[i], keyValues[i + 1]);
}
Edit: People in the C# tag are damn fast...
If you have Rx as a dependency you can do:
strings
.BufferWithCount(2)
.ToDictionary(
buffer => buffer.First(), // key selector
buffer => buffer.Last()); // value selector
BufferWithCount(int count) takes the first count values from the input sequence and yield them as a list, then it takes the next count values and so on. I.e. from your input sequence you will get the pairs as lists: {"^BI", "connectORCL"}, {"^CR", "connectCR"}, the ToDictionary then takes the first list item as key and the last ( == second for lists of two items) as value.
However, if you don't use Rx, you can use this implementation of BufferWithCount:
static class EnumerableX
{
public static IEnumerable<IList<T>> BufferWithCount<T>(this IEnumerable<T> source, int count)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (count <= 0)
{
throw new ArgumentOutOfRangeException("count");
}
var buffer = new List<T>();
foreach (var t in source)
{
buffer.Add(t);
if (buffer.Count == count)
{
yield return buffer;
buffer = new List<T>();
}
}
if (buffer.Count > 0)
{
yield return buffer;
}
}
}
It looks like other people have already beaten me to it and/or have more efficient answers but I'm posting 2 ways:
A for loop might be the clearest way to accomplish in this case...
var words = new[] { "^BI", "connectORCL", "^CR", "connectCR" };
var final = words.Where((w, i) => i % 2 == 0)
.Select((w, i) => new[] { w, words[(i * 2) + 1] })
.ToDictionary(arr => arr[0], arr => arr[1])
;
final.Dump();
//alternate way using zip
var As = words.Where((w, i) => i % 2 == 0);
var Bs = words.Where((w, i) => i % 2 == 1);
var dictionary = new Dictionary<string, string>(As.Count());
var pairs = As.Zip(Bs, (first, second) => new[] {first, second})
.ToDictionary(arr => arr[0], arr => arr[1])
;
pairs.Dump();
FYI, this is what I ended up with using a loop and implementing it as an extension method:
internal static Boolean IsEven(this Int32 #this)
{
return #this % 2 == 0;
}
internal static IDictionary<String, String> ToDictionary(this String[] #this)
{
if (!#this.Length.IsEven())
throw new ArgumentException( "Array doesn't contain an even number of entries" );
var dictionary = new Dictionary<String, String>();
for (var i = 0; i < #this.Length; i += 2)
{
var key = #this[i];
var value = #this[i + 1];
dictionary.Add(key, value);
}
return dictionary;
}
Pure Linq
Select : Project original string value and its index.
GroupBy : Group adjacent pairs.
Convert each group into dictionary entry.
string[] arr = new string[] { "^BI", "connectORCL", "^CR", "connectCR" };
var dictionary = arr.Select((value,i) => new {Value = value,Index = i})
.GroupBy(value => value.Index / 2)
.ToDictionary(g => g.FirstOrDefault().Value,
g => g.Skip(1).FirstOrDefault().Value);

Categories

Resources