algorithm searching through dictionary - c#

Im working from the Q https://www.testdome.com/for-developers/solve-question/10282
Write a function that, given a list and a target sum, returns zero-based indices of any two distinct elements whose sum is equal to the target sum. If there are no such elements, the function should return null.
For example, FindTwoSum(new List<int>() { 1, 3, 5, 7, 9 }, 12) should return a Tuple<int, int> containing any of the following pairs of indices:
1 and 4 (3 + 9 = 12)
2 and 3 (5 + 7 = 12)
3 and 2 (7 + 5 = 12)
4 and 1 (9 + 3 = 12)
So far iv got:
class TwoSum
{
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
//throw new NotImplementedException("Waiting to be implemented.");
IList<int> duplicateList = list;
foreach (int i in list)
{
foreach (int j in duplicateList)
{
if (i != j)
{
if (i + j == sum)
{
return Tuple.Create(i, j);
}
}
}
}
return null;
}
public static void Main(string[] args)
{
Tuple<int, int> indices = FindTwoSum(new List<int>() { 1, 3, 5, 7, 9 }, 12);
Console.WriteLine(indices.Item1 + " " + indices.Item2);
}
}
This returns the correct answer in my code but is failing 3 out of 4 cases in the quesitong because:
Example case: Wrong answer
No solution: Correct answer
One solution: Wrong answer
Performance test with a large number of elements: Wrong answer
Ive looked at the hints
Hint 1: Nested for loops can iterate over the list and calculate a sum in O(N^2) time.
Hint 2: A dictionary can be used to store pre-calculated values, this may allow a solution with O(N) complexity.
So im using nested loops but Im guessing in this instance in order to pass hint2 I need to use a dictionary...How can I refactor this into using a dictionary?
Thanks for any help!

You are not returning indexes, you are returning values. for loops are not foreach loops.
A nested for loops solution would be something like this:
for(int i=0; i<list.Count-1; i++)
{
for(int j=i+1;j<list.Count;j++)
{
if(list[i]+list[j] == sum)
{
return Tuple.Create(i, j);
}
}
}
return null;
I'll leave the dictionary solution for you to create.

Hi this one received 50%
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
int n = list.Count-1;
while(n != 0)
{
for (int i = 0; i <= list.Count-1 ; i++)
{
if (list[n] + list[i] == sum)
{
return Tuple.Create(i, n);
}
}
n--;
}
return null;
}
// get list value:
var aat = (from l1 in list
from l2 in list
where l1 + l2 == 12
group new { l1, l2} by new { l1, l2 } into gp
select new {gp.Key}).ToDictionary( a => a.Key.l1, b => b.Key.l2 );
// get list index of the value:
var aav = (from l1 in list
from l2 in list
where l1 + l2 == 12
group new { l1, l2 } by new { l1, l2 } into gp
select new { gp.Key })
.ToDictionary( a => list.IndexOf(a.Key.l1), b => list.IndexOf(b.Key.l2)
);

Related

Get the max count of an array inside array?

I have an array inside the array and I want to get the Highest count of that Array,
List<int> badnumber = new List<int>() { 5,4,2, 15 };
int lower = 1;
int upper = 10;
int count = 0;
List<int> goodnumber = new List<int>();
List<List<int>> myList = new List<List<int>>();
for (int i = lower; i <= upper; i++)
{
if (!badnumber.Contains(i))
{
if (!goodnumber.Contains(i))
goodnumber.Add(i);
}
else
{
myList.Add(goodnumber);
goodnumber = new List<int>();
}
if (i == upper) {
myList.Add(goodnumber);
}
}
in myList values are like this
Array 1 : { 1 }
Array 2 : { 3 }
Array 3 : { 0 }
Array 4 : { 6, 7, 8, 9, 10 }
I want to get the count of the highest sequence which is Array 4. and return the count of it which is 5.
how would I get that?
Use following sample
var maxCount = myList.Max(l => l.Count);
Try following :
List<List<int>> myList = new List<List<int>>() {
new List<int> { 1},
new List<int> { 3},
new List<int> { 0},
new List<int> { 6,7,8,9,10}
};
int results = myList.Max(x => x.Count);
Basically your task boils down to the following:
How to get the greatest number in a list
In order to achieve that, you have to iterate that (outer) list, get every elements member you want to compare - in your case the Count - and check if it is greater the current Max:
int max = 0;
foreach(var l in myList)
{
if(l.Count > max)
max = l.Count;
}
or even simpler using linq, see jdweng.
Try below lambda to get index position with count:
int index = 0;
var result = myList.Select(x => new { indexPos = ++index, x.Count }).OrderByDescending(x => x.Count).First();

Linq Union/UnionAll/Concat

I'm trying to convert a simple piece of Math to Linq.
I want to bundle together the prime factors for several numbers into one collection.
Consider the following integers.
8 = 2 * 2 * 2
12 = 2 * 2 * 3
The smallest number divisible by both 8 & 12 is 24, so I'd like the resultant group to contain
{ 2, 2, 2, 3 }
If I use Concat the result is {2,2,2,2,2,3} - not correct
If I use Union the result is {2,3} - not correct
Is there a built in Linq Set Manipulation function which will recognise that it needs to keep the maximum number of occurences of an item (i.e. not add another if there are already enough there to satisfy if & add another if there aren't)
Well, it's not any existing function, as I don't think such exists, but pretty simple code is capable of handling this:
var listA = new List<int> {2, 2, 2};
var listB = new List<int> {2, 2, 3};
var grouppedA = listA.GroupBy(i => i).Select(g => new { key = g.Key, count = g.Count()});
var grouppedB = listB.GroupBy(i => i).Select(g => new { key = g.Key, count = g.Count()});
var result = grouppedA
.Union(grouppedB)
.GroupBy(g => g.key)
.SelectMany(g => Enumerable.Repeat(g.Key, g.Max(h => h.count)));
foreach (int i in result)
{
Console.Write(i + " ");
}
Console.ReadKey();
Output:
2 2 2 3
using System;
using System.Collections.Generic;
public class Sample {
public static void Main(String[] args) {
var n8 = toFactors(8);
var n12 = toFactors(12);
var uf = unionFactors(n8, n12);//LCM
printFactors(uf);
}
public static void printFactors(Dictionary<long, int> factors){
Console.Write("{ ");
foreach(var factor in factors.Keys){
for(int i=0;i<factors[factor];++i)
Console.Write( factor + " ");
}
Console.WriteLine("}");
}
public static Dictionary<long, int> unionFactors(Dictionary<long, int> af, Dictionary<long, int> bf){
Dictionary<long, int> uf = new Dictionary<long, int>();
foreach(var kv in af){
uf.Add(kv.Key, kv.Value);//copy
}
foreach(var kv in bf){
if(uf.ContainsKey(kv.Key)){
if(kv.Value > uf[kv.Key])//max
uf[kv.Key] = kv.Value;
} else {
uf.Add(kv.Key, kv.Value);
}
}
return uf;
}
public static Dictionary<long, int> toFactors(long num){
var factors = new Dictionary<long, int>();
long n = num, i = 2, sqi = 4;
while(sqi <= n){
while(n % i == 0){
n /= i;
if(factors.ContainsKey(i)){
factors[i] += 1;
} else {
factors.Add(i, 1);
}
}
sqi += 2 * (i++) + 1;
}
if(n != 1 && n != num){
if(factors.ContainsKey(i)){
factors[i] += 1;
} else {
factors.Add(i, 1);
}
}
if(factors.Count == 0)
factors.Add(num, 1);//prime
return factors;
}
}

Iterating through c# array & placing objects sequentially into other arrays

Okay, so this seems simple, but I can't think of a straightforward solution;
Basically I have an object array in C# that contains, say, 102 elements. I then also have 4 other empty arrays. I want to iterate through the original array and distribute the 100 elements evenly, then distribute 101 and 102 to the 1st and 2nd new arrays respectively.
int i = 1,a=0, b=0, c=0, d = 0;
foreach (ReviewStatus data in routingData)
{
if (i == 1)
{
threadOneWork[a] = data;
a++;
}
if (i == 2)
{
threadTwoWork[b] = data;
b++;
}
if (i == 3)
{
threadThreeWork[c] = data;
c++;
}
if (i == 4)
{
threadFourWork[d] = data;
d++;
i = 0;
}
i++;
}
Now the above code definitely works, but I was curious, does anybody know of a better way to do this??
var workArrays = new[] {
threadOneWork,
threadTwoWork,
threadThreeWork,
threadFourWork,
};
for(int i=0; i<routingData.Length; i++) {
workArrays[i%4][i/4] = routingData[i];
}
Put the four arrays into an array of arrays, and use i%4 as an index. Assuming that thread###Work arrays have enough space to store the data, you can do this:
var tw = new[] {threadOneWork, threadTwoWork, threadThreeWork, threadFourWork};
var i = 0;
foreach (ReviewStatus data in routingData) {
tw[i%4][i/tw.Length] = data;
i++;
}
Linq is your friend! Use modulo to group the items via the total number of arrays in your case 4.
For example the code splits them up into four different lists:
var Items = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Items.Select( ( i, index ) => new {
category = index % 4,
value = i
} )
.GroupBy( itm => itm.category, itm => itm.value )
.ToList()
.ForEach( gr => Console.WriteLine("Group {0} : {1}", gr.Key, string.Join(",", gr)));
/* output
Group 0 : 1,5,9
Group 1 : 2,6,10
Group 2 : 3,7
Group 3 : 4,8
*/

LINQ method to group collection into subgroups with specified number of elements

Does there exist a LINQ method to group a given collection into subgroups with specified number of elements I mean, something like Scala's grouped method.
e.g. in Scala, List(89, 67, 34, 11, 34).grouped(2) gives List(List(89, 67), List(34, 11), List(34)).
In case such a method doesn't exist, what would be the LINQ way to do it?
Yes, you can. But you can argue if it's very pretty...
Int64[] aValues = new Int64[] { 1, 2, 3, 4, 5, 6 };
var result = aValues
.Select( ( x, y ) => new KeyValuePair<Int64, Int32>( x, y ) )
.GroupBy( x => x.Value / 2 )
.Select( x => x.Select( y => y.Key ).ToList() ).ToList();
How it works:
Select x and y from the original collection, where x is the actual value and y is the index of it in the given collection. Then group by integer devision of the index and the desired grouping length ( in this example 2 ).
Grouping by integer devision will round up to the lower - so 0 / 2 = 0, 1 / 2 = 0, etc. which will give us the needed grouping category value. This is what we are grouping against here.
For result select only the values grouped in lists and return them as a collection of lists.
Here is a website that seems to have some sample code to do what you want:
http://www.chinhdo.com/20080515/chunking/
So what you could do is take this method and create an extension method.
Extension method sample:
static class ListExtension
{
public static List<List<T>> BreakIntoChunks<T>(this List<T> list, int chunkSize)
{
if (chunkSize <= 0)
{
throw new ArgumentException("chunkSize must be greater than 0.");
}
List<List<T>> retVal = new List<List<T>>();
while (list.Count > 0)
{
int count = list.Count > chunkSize ? chunkSize : list.Count;
retVal.Add(list.GetRange(0, count));
list.RemoveRange(0, count);
}
return retVal;
}
}
You could try the approach shown in this answer to this similar question.
public static class GroupingExtension
{
public static IEnumerable<IEnumerable<T>> Grouped<T>(
this IEnumerable<T> input,
int groupCount)
{
if (input == null) throw new ArgumentException("input");
if (groupCount < 1) throw new ArgumentException("groupCount");
IEnumerator<T> e = input.GetEnumerator();
while (true)
{
List<T> l = new List<T>();
for (int n = 0; n < groupCount; ++n)
{
if (!e.MoveNext())
{
if (n != 0)
{
yield return l;
}
yield break;
}
l.Add(e.Current);
}
yield return l;
}
}
}
Use like this:
List<int> l = new List<int>{89, 67, 34, 11, 34};
foreach (IEnumerable<int> group in l.Grouped(2)) {
string s = string.Join(", ", group.Select(x => x.ToString()).ToArray());
Console.WriteLine(s);
}
Result:
89, 67
34, 11
34

Selecting unique elements from a List in C#

How do I select the unique elements from the list {0, 1, 2, 2, 2, 3, 4, 4, 5} so that I get {0, 1, 3, 5}, effectively removing all instances of the repeated elements {2, 4}?
var numbers = new[] { 0, 1, 2, 2, 2, 3, 4, 4, 5 };
var uniqueNumbers =
from n in numbers
group n by n into nGroup
where nGroup.Count() == 1
select nGroup.Key;
// { 0, 1, 3, 5 }
var nums = new int{ 0...4,4,5};
var distinct = nums.Distinct();
make sure you're using Linq and .NET framework 3.5.
With lambda..
var all = new[] {0,1,1,2,3,4,4,4,5,6,7,8,8}.ToList();
var unique = all.GroupBy(i => i).Where(i => i.Count() == 1).Select(i=>i.Key);
C# 2.0 solution:
static IEnumerable<T> GetUniques<T>(IEnumerable<T> things)
{
Dictionary<T, int> counts = new Dictionary<T, int>();
foreach (T item in things)
{
int count;
if (counts.TryGetValue(item, out count))
counts[item] = ++count;
else
counts.Add(item, 1);
}
foreach (KeyValuePair<T, int> kvp in counts)
{
if (kvp.Value == 1)
yield return kvp.Key;
}
}
Here is another way that works if you have complex type objects in your List and want to get the unique values of a property:
var uniqueValues= myItems.Select(k => k.MyProperty)
.GroupBy(g => g)
.Where(c => c.Count() == 1)
.Select(k => k.Key)
.ToList();
Or to get distinct values:
var distinctValues = myItems.Select(p => p.MyProperty)
.Distinct()
.ToList();
If your property is also a complex type you can create a custom comparer for the Distinct(), such as Distinct(OrderComparer), where OrderComparer could look like:
public class OrderComparer : IEqualityComparer<Order>
{
public bool Equals(Order o1, Order o2)
{
return o1.OrderID == o2.OrderID;
}
public int GetHashCode(Order obj)
{
return obj.OrderID.GetHashCode();
}
}
If Linq isn't available to you because you have to support legacy code that can't be upgraded, then declare a Dictionary, where the first int is the number and the second int is the number of occurences. Loop through your List, loading up your Dictionary. When you're done, loop through your Dictionary selecting only those elements where the number of occurences is 1.
I believe Matt meant to say:
static IEnumerable<T> GetUniques<T>(IEnumerable<T> things)
{
Dictionary<T, bool> uniques = new Dictionary<T, bool>();
foreach (T item in things)
{
if (!(uniques.ContainsKey(item)))
{
uniques.Add(item, true);
}
}
return uniques.Keys;
}
There are many ways to skin a cat, but HashSet seems made for the task here.
var numbers = new[] { 0, 1, 2, 2, 2, 3, 4, 4, 5 };
HashSet<int> r = new HashSet<int>(numbers);
foreach( int i in r ) {
Console.Write( "{0} ", i );
}
The output:
0 1 2 3 4 5
Here's a solution with no LINQ:
var numbers = new[] { 0, 1, 2, 2, 2, 3, 4, 4, 5 };
// This assumes the numbers are sorted
var noRepeats = new List<int>();
int temp = numbers[0]; // Or .First() if using IEnumerable
var count = 1;
for(int i = 1; i < numbers.Length; i++) // Or foreach (var n in numbers.Skip(1)) if using IEnumerable
{
if (numbers[i] == temp) count++;
else
{
if(count == 1) noRepeats.Add(temp);
temp = numbers[i];
count = 1;
}
}
if(count == 1) noRepeats.Add(temp);
Console.WriteLine($"[{string.Join(separator: ",", values: numbers)}] -> [{string.Join(separator: ",", values: noRepeats)}]");
This prints:
[0,1,2,2,2,3,4,4,5] -> [0,1,3,5]
In .Net 2.0 I`m pretty sure about this solution:
public IEnumerable<T> Distinct<T>(IEnumerable<T> source)
{
List<T> uniques = new List<T>();
foreach (T item in source)
{
if (!uniques.Contains(item)) uniques.Add(item);
}
return uniques;
}

Categories