Search for list of integers within another list C# - c#

I would like to find all the occurances of my source list in my dictionary.
Currently, I'm looping through my dictionary, and comparing each value of dictionary.
Dictionary<string, list<int>> refList.
List<int> sourceList.
foreach(KeyValuePair<string, List<int>> kvp in refDict)
{
List<int> refList = (List<int>)kvp.Value;
bool isMatch = (refList.Count == sourceList.Count && refList.SequenceEqual(sourceList));
if (isMatch)
{
......
......
}
}
I would like to find the indexes in my dict of all the occurances of my source list.

I do not understand why you need a position (not an index!) of dictionary items because order of items is non deterministic, MSDN:
For purposes of enumeration, each item in the dictionary is treated as
a KeyValuePair structure representing a value and its
key. The order in which the items are returned is undefined.
but anyways:
Prepare data:
IDictionary<string, List<int>> refDict = new Dictionary<string, List<int>>
{
{"item1", new List<int> {1, 2, 3}},
{"item2", new List<int> {4, 5, 6}},
{"item3", new List<int> {1, 2, 3}}
};
List<int> sourceList = new List<int> {1, 2, 3};
Search for indexes:
var indexes = refDict.Values
.Select((list, index) => list.SequenceEqual(sourceList) ? index : -1)
.Where(x => x >= 0);
Search for keys:
var keys = refDict
.Where(item => item.Value.SequenceEqual(sourceList))
.Select(item => item.Key);

var list = new List<int> { 1,2,3 };
var dico = new Dictionary<string, List<int>>();
dico.Add("A", list);
dico.Add("B", new List<int> { 2,3 });
dico.Add("C", new List<int> { 1,2,3 });
var keys = dico.Where (d => d.Value.SequenceEqual(list)).Select (d => d.Key);
Pay attention that this wil return "A" and "C" !!!

Related

How get unmatched list from dictionary

I want to get unmatched dictionary based on list item using LINQ. Please refer my sample code
Dictionary<string, List<int>> lowerActionRoles = new Dictionary<string, List<int>>();
Dictionary<string, List<int>> upperActionRoles = new Dictionary<string, List<int>>();
lowerActionRoles.Add("11", new List<int>() { 1, 2, 4 });
upperActionRoles.Add("11", new List<int>() { 1, 2, 4, 5 });
lowerActionRoles.Add("13", new List<int>() { 1, 2, 4 });
lowerActionRoles.Add("21", new List<int>() { 1, 2, 4 });
upperActionRoles.Add("21", new List<int>() { 1, 2, 4 });
Here I have 2 dictionary lowerActionRoles and upperActionRoles. Dictionary with key 21 matched and key 11 is not matched. Here I want get dictionary with key 11.
Based on the assumption that items in only one of the dictionaries should be ignored:
lowerActionRoles.Where(entry =>
{
if (upperActionRoles.TryGet(entry.Key, out List<int> upperActionList))
{
return !upperActionList.SequenceEqual(entry.Value);
}
else
{
return false;
}
}
This will return you a collection of entries in lowerActionRoles (IEnumerable<KeyValuePair<string, List<int>>>).
If you're interested only in the keys, add
.Select(entry => entry.Key);
to the previous query
and to convert to a new dictionary:
.ToDictionary(entry => entry.Key, entry => entry.Value);
You can test if there is key present in both of dictionaries by using ContainsKey and then for checking values of that list by using SequenceEqual like
var result = upperActionRoles
.Where(entry => lowerActionRoles.ContainsKey(entry.Key) && !lowerActionRoles[entry.Key].SequenceEqual(entry.Value))
.ToDictionary(entry => entry.Key, entry => entry.Value);
And to display your result on the console window,
foreach (var item in result)
{
Console.WriteLine("Key: " + item.Key);
Console.WriteLine();
item.Value.ForEach(x => Console.WriteLine("Value: " + x));
}
Console.ReadLine();
Output:
Note: If you want to get a list from another dictionary then just switch the dictionaries name on above query.

LINQ: Convert Dictionary<int, List<MyObject>> to List<List<string>>

My Dictionary<int, List<MyObject>> result has..
Key Value
1 {"Chicago", 100}
1 {"Newyork", 200}
2 {"Minneapolis", 300}
want to convert it to List<List<string>> in below format.
{"Index", "City","Value"},
{1, "Chicago", 100},
{1, "Newyork", 200}
{2, "Minneapolis", 300}
This is what I have achieved so far
var list = result.Select(rec => new
{
Index = rec.Key,
City = rec.Value.Select(rec1 => rec1.City),
Value = rec.Value.Select(rec1 => rec1.Value)
}).ToList();
What I am getting is this..
{"Index", "City", "Value"},
{1, System.Linq.Enumerable.WhereSelectListIterator<MyObject, string>, System.Linq.Enumerable.WhereSelectListIterator<MyObject, int>},
{1, System.Linq.Enumerable.WhereSelectListIterator<MyObject, string>, System.Linq.Enumerable.WhereSelectListIterator<MyObject, int>},
{2, System.Linq.Enumerable.WhereSelectListIterator<MyObject, string>, System.Linq.Enumerable.WhereSelectListIterator<MyObject, int>}
May be I am missing Where condition. Please suggest.
public class MyObject
{
public MyObject(){}
public string City{get;set;}
public int Value{get;set;}
}
This is what you need:
var Result = result.SelectMany(r => r.Value.Select(x => new[] { r.Key.ToString(), x.City, x.Value.ToString() }.ToList()));
To prepend column names as the first element of the outer list:
Result.Insert(0, {"Index", "City","Value"}.ToList());
Do you need the output like this?
I have a solution for you. Try it.
Dictionary<int, List<MyObject>> result = new Dictionary<int, List<MyObject>>();
result.Add(1, new List<MyObject>() { new MyObject() { City = "Chicago", Value = 100 }, new MyObject() { City = "Newyork", Value = 200 } });
result.Add(2, new List<MyObject>() { new MyObject() { City = "Minneapolis", Value = 300 } });
var resultYouWant = result.SelectMany(p => p.Value.Select(a => new { Index = p.Key, a.City, a.Value })).ToList();
below code is work for you but not getting what is your usecase.
var list = result.Select(rec => new
{
Index = rec.Key,
City = rec.Value.City),
Value = rec.Value.Value)
}).ToList();
City = rec.Value.Select(rec1 => rec1.City),
That is creating an IEnumerable, not a string. Which is why you get System.Linq.Enumerable.WhereSelectListIterator out of it.
You may be better off using for loops here.
foreach(var kvp in result)
foreach(var value in kvp)
//Create string here and add it to your list.

linq: how to divide a list into two by the sum of the values and keeping the input order

With LINQ I do not know how to split a list of items in two lists in which the sum of the values has the lowest gap possible while preserving the order of the input list.
Using this list as an example:
key value
A 5
B 2
C 3
D 4
E 1
The result should be the following
list1 = A, B (sum=7)
list2 = C, D, E (sum=8)
With this other list
key value
A 1
B 1
C 1
D 1
E 9
The result should be the following
list1 = A, B, C, D (sum=4)
list2 = E (sum=9)
Thank's in advance to those who will provide me with directions.
sf
Logic goes as:
Fetch max item and min item (min item should not be equal to max item) from original list
Add max item to list having smaller sum
Remove max and min items from original lists
last single item goes to list having lesser sum.
List<Data> list = new List<Data>()
{
new Data { Key="A",Val=9 },
new Data { Key="B",Val=1 },
new Data { Key="D",Val=1 },
new Data { Key="C",Val=1 },
new Data { Key="E",Val=1 }
};
List<Data> list1 = new List<Data>();
List<Data> list2 = new List<Data>();
while (list.Any())
{
var max = list.Max(p => p.Val);
var min = list.Min(p => p.Val);
var maxItem = list.FirstOrDefault(p => p.Val == max);
var minItem = list.FirstOrDefault(p => p.Val == min && max != min);
if (maxItem == null)
{
if (list1.Sum(p => p.Val) < list2.Sum(p => p.Val))
list1.Add(minItem);
else
list2.Add(minItem);
}
else if(minItem == null)
{
if (list1.Sum(p => p.Val) < list2.Sum(p => p.Val))
list1.Add(maxItem);
else
list2.Add(maxItem);
}
else
{
if (list1.Sum(p => p.Val) < list2.Sum(p => p.Val))
{
list1.Add(maxItem);
list2.Add(minItem);
}
else
{
list2.Add(maxItem);
list1.Add(minItem);
}
}
list.Remove(minItem);
list.Remove(maxItem);
}
var sumList1 = list1.Sum(p => p.Val);
var sumList2 = list2.Sum(p => p.Val);
You can use a for-loop:
int minDelta = int.MaxValue;
var list1 = new List<ClassName>();
var list2 = new List<ClassName>();
for (int i = 0; i < list.Count - 1; i++)
{
int count = i + 1;
int sum1 = list.Take(count).Sum(x => x.Value);
int sum2 = list.Skip(count).Sum(x => x.Value);
int delta = Math.Abs(sum1 - sum2);
if (delta < minDelta)
{
minDelta = delta;
list1 = list.Take(count).ToList();
list2 = list.Skip(count).ToList();
}
}
Using Linq and a few dictionarys (one sorted).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication85
{
class Program
{
static void Main(string[] args)
{
int index = 0;
List<string> list1 = null;
List<string> list2 = null;
Dictionary<string,int> dict1 = new Dictionary<string,int>() {
{"A", 5},
{"B", 2},
{"C", 3},
{"D", 4},
{"E", 1}
};
index = ReturnSmallestDiffIndex(dict1.AsEnumerable().Select(x => x.Value).ToList());
list1 = dict1.AsEnumerable().Take(index).Select(x => x.Key).ToList();
list2 = dict1.AsEnumerable().Skip(index).Take(dict1.Count - index).Select(x => x.Key).ToList();
Dictionary<string, int> dict2 = new Dictionary<string, int>() {
{"A", 1},
{"B", 1},
{"C", 1},
{"D", 1},
{"E", 9}
};
index = ReturnSmallestDiffIndex(dict2.AsEnumerable().Select(x => x.Value).ToList());
list1 = dict1.AsEnumerable().Take(index).Select(x => x.Key).ToList();
list2 = dict1.AsEnumerable().Skip(index).Take(dict1.Count - index).Select(x => x.Key).ToList();
}
static int ReturnSmallestDiffIndex(List<int> input)
{
SortedDictionary<int, List<int>> dict = new SortedDictionary<int, List<int>>();
for(int index = 1; index < input.Count; index++)
{
int diff = input.Skip(index).Take(input.Count - index).Sum() - input.Take(index).Sum();
if(dict.ContainsKey(Math.Abs(diff)))
{
dict[Math.Abs(diff)].Add(index);
}
else
{
dict.Add(Math.Abs(diff), new List<int>() {index});
}
}
return dict.AsEnumerable().FirstOrDefault().Value.FirstOrDefault();
}
}
}
Not efficient but Linq-heavy solution:
var values = new[] { 5, 2, 3, 4, 1 };
int[] sums = values.Select((element, index) => values.Skip(index).Sum()).ToArray();
int[] reverseSums = values.Select((element, index) => values.Take(index).Sum()).ToArray();
int[] diffs = sums.Select((element, index) => Math.Abs(element - reverseSums[index])).ToArray();
int minDiff = diffs.Min();
int[] firstPart = values.TakeWhile((element, index) => diffs[index] > minDiff).ToArray();
int[] lastPart = values.Skip(firstPart.Length).ToArray();
Dictionary<string, int> dict1 = new Dictionary<string, int>()
{
{"A", 5},
{"B", 2},
{"C", 3},
{"D", 4},
{"E", 1}
};
var result = Enumerable.Range(1, dict1.Count - 1).Select(i =>
{
var first = dict1.Take(i);
var second = dict1.Skip(i);
int diff = Math.Abs(first.Sum(x => x.Value) - second.Sum(x => x.Value));
return new {First = first, Second = second, Diff = diff};
}).OrderBy(x => x.Diff).First();
Console.WriteLine(result.Diff);
Console.WriteLine(string.Join(" ", result.First.Select(x => x.Value)));
Console.WriteLine(string.Join(" ", result.Second.Select(x => x.Value)));
I don't know if this is the fastest way, but here is what it does:
I try each possibility (i being the splitting index I iterate over)
for every splitting index i I split the dictionary and calculate the diff
I order the resulting objects by that diff
and finally take the first one
This is of course not very performance optimized, as I have to build the sums for all possibilities. One improvement could be to start in the middle instead of i = 1

How to efficiently prune a list based on "is-subset" condition?

Let's suppose I am given Dictionary<int, List<int>> and I want to prune it using the following condition
an item should be removed from the dictionary if there exists an itemLarger != item in the dictionary such that item.Value.Union(new[] { item.Key }) is a subset of itemLarger.Value.Union(new[] { itemLarger.Key })
That is, each item in the dictionary will be represented by a list of numbers obtained by appending the item's key to the item's value and I want to get rid of those items which are represented by a subset of some other item's representation.
Example:
var testResult = new Dictionary<int, List<int>>
{
{ 2, new[] { 3, 4 }},
{ 3, new[] { 2, 4 }},
{ 1, new[] { 2, 3, 4 }},
{ 4, new[] { 2, 3 }}
};
In this case, the only element left in the list would be {1, {2, 3, 4}}
I can't seem to find some elegant way to do it, since
GroupBy does not allow me to specify which element in particular should be used as the key when I have two that should be groupped
Distinct does not allow me to specify, in case two elements are not distinct, which of them should be kept in the list
Of course it is doable in a trivial way. I wonder if there is some nice one.
Thank you for any ideas.
I don't think this will be much different from the "trivial" way you meant, but here's a LINQ solution:
var sets = testResult
.Select(x => new { Key = x.Key, Set = new HashSet<int>(x.Value.Concat(new[] { x.Key })) })
.ToList();
var res = sets.Where(s => sets.Any(x => x.Set.IsSupersetOf(s.Set) && x.Key != s.Key));
var keysToRemove = res.Select(x => x.Key);
This might not be the most effective way but it's short and kind of readable.
var test = new Dictionary<int, List<int>>
{
{ 2, new List<int> { 3, 4 }},
{ 3, new List<int> { 2, 4 }},
{ 1, new List<int> { 2, 3, 4 }},
{ 4, new List<int> { 2, 3 }}
};
var res = test.Where(n => !test.Any(m => m.Key!=n.Key && n.Value.Intersect(m.Value).Count()==n.Value.Count) );
In my solution I check for each element x in testResult if this element is subset of any other element in testResult. If it isn't, this element pass 'where' filter in linq expression. Two last lines are conversion of result from list representation to dictionary representation.
var listResult =
(from x in testResult
where (from y in testResult
where !x.Value.Except(y.Value).Any() && x.Key != y.Key
select y).Count() == 0
select x).ToList();
var dictionaryResult = new Dictionary<int, List<int>>();
listResult.ForEach(x => dictionaryResult.Add(x.Key, x.Value));
Edit:
We could write it even shorter:
testResult = testResult.Where(x =>
(from y in testResult
where !x.Value.Except(y.Value).Any() && x.Key != y.Key
select y).Count() == 0).ToDictionary(x => x.Key, x => x.Value);

Merging 3 dictionaries into single dictionary

I have the following
Dictionary<string,string> dict1 has 3 items
"A"="1.1"
"B"="2.1"
"C"="3.1"
Dictionary<string,string> dict2 has 3 items
"A"="1.2"
"B"="2.2"
"C"="3.2"
Dictionary<string,string> dict2 has 3 items
"A"="1.3"
"B"="2.3"
"C"="3.3"
I want a final Dict dictFinal which is of type Dictionary<string,string[]>
"A"="1.1,1.2,1.3"
"B"="2.1,2.2,2.3"
"C"="3.1,3.2,3.3"
Given similar keys, provide a collection of all the dictionaries and use SelectMany to handle a dynamic number of array items:
var dictionaries = new[] { dict1, dict2, dict3 };
var result = dictionaries.SelectMany(dict => dict)
.GroupBy(o => o.Key)
.ToDictionary(g => g.Key,
g => g.Select(o => o.Value).ToArray());
The dictionaries type could be a List<T> not necessarily an array as above. The important thing is that you group them together in a collection in order to LINQ over them.
Assuming all 3 dictionaries have the same keys, the following should do the job:
var d1 = new Dictionary<string, string>()
{
{"A", "1.1"},
{"B", "2.1"},
{"C", "3.1"}
};
var d2 = new Dictionary<string, string>()
{
{"A", "1.2"},
{"B", "2.2"},
{"C", "3.2"}
};
var d3 = new Dictionary<string, string>()
{
{"A", "1.3"},
{"B", "2.3"},
{"C", "3.3"}
};
var result = d1.Keys.ToDictionary(k => k, v => new[] {d1[v], d2[v], d3[v]});
Assuming all have the same keys the most straigt forward way is:
Dictionary<string,string[]> result = new Dictionary<string,string[]>();
foreach(var key in dict1.Keys)
{
result[key] = new string[]{dict1[key], dict2[key], dict3[key]};
}

Categories

Resources