Extension method Average() C# - c#

First of all you all need to know that I don't want to use the LINQ library in C#.
Now I want to write an Extension method that returns the average of different lists. This are the lists
integers = new List<int> { 5, 76, 3, 93, 143, 5, 11, 67, 5 };
doubles = new List<double> { 1.23, 68.256, 44.55, 96.127, 393.4567, 2.45, 4.1 };
persons = new List<Person>
{
new Person {Firstname = "John", Lastname = "last", Age = 66, Sallary = 1513},
new Person {Firstname = "Donald", Lastname = "last", Age = 77, Sallary = 3100}
};
This is what I already got:
public static double Average(this IEnumerable<int> source)
{
IList<int> list = source as IList<int>;
if (source == null) throw new ArgumentNullException("Err");
long sum = 0;
for (int i = 0; i < list.Count; i++)
{
sum += list[i];
}
return sum / list.Count;
}
I am only able to calculate the average of my integer list. I also want to calculate the average of the double list and the average salary of my persons list.
This is how I will call the function where the persons list average salary should be calculated
persons.Average(x => x.Sallary).ShowSingle("persons.Average(x => x.Sallary)");

First, your Average method returns the wrong result for the integer list since you are using integer division (it returns 45 instead of 45.3333).
To make it work with double, you need to create an overload that is using IEnumerable<double> etc.
public static double Average(this IEnumerable<double> source)
{
IList<double> list = source as IList<double>;
if (source == null || source.Count == 0)
throw new ArgumentNullException("Err");
double sum = 0;
for (int i = 0; i < list.Count; i++)
{
sum += list[i];
}
return sum / list.Count;
}
You can simplify the method a bit by using foreach:
public static double Average(this IEnumerable<double> source)
{
if (source == null)
throw new ArgumentNullException("Err");
double sum = 0;
int count = 0;
foreach (double entry in source)
{
sum += entry;
count+=1;
}
if (count == 0) return 0;
return sum / count;
}

Like written in my comment you can use the implementation from the Linq repository. I have just changed the way how they process it on 0 count of items.
public static double Average(this IEnumerable<int> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
long sum = 0;
long count = 0;
checked
{
foreach (int v in source)
{
sum += v;
count++;
}
}
if (count == 0)
{
return 0;
}
return (double)sum / count;
}
public static double Average<T>(this IEnumerable<T> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if(typeof(T) != typeof(int)
&& typeof(T) != typeof(double)
&& typeof(T) != typeof(float)
&& typeof(T) != typeof(decimal)
&& typeof(T) != typeof(long))
{
throw new InvalidOperationException($"Wrong type specified: {typeof(T)}");
}
double sum = 0;
long count = 0;
checked
{
foreach (T v in source)
{
sum += Convert.ToDouble(v);
count++;
}
}
if (count == 0)
{
return 0;
}
return (double)sum / count;
}
A working example can be opened here
And of course the original Linq code can be found here

I am only able to calculate the average of my integer list. I also want to calculate the average of the double list and the average salary of my persons list.
As already mentioned in the comments by a few user's, it would be best to extract this into separate routines. As Klaus mentioned above, Compile-time checking is always better than run-time checking (better performance, better and earlier diagnostics). I agree, but as I mentioned on another answer, does this mean it's bad design from the programmer and or bad object oriented design on the authors?
Here's a little sample using generics (<T>), one routine does the int and double list and the other (for Person) is extracted out to it's own routine. The first Average routine uses the help of Convert.ChangeType to return specified type whose value is equivalent to a specified object.
public static class Extensions
{
public static T Average<T>(this IEnumerable<T> source)
{
double dblSum = 0;
int intSum = 0;
if (source == null)
throw new ArgumentNullException("Err");
if (typeof(T) == typeof(int) && source is List<int> intList && intList.Count > 0)
{
for (int i = 0; i < intList.Count; i++)
{
intSum += intList[i];
}
return (T)Convert.ChangeType((intSum / intList.Count), typeof(T));
}
else if (typeof(T) == typeof(double) && source is List<double> dblList && dblList.Count > 0)
{
for (int i = 0; i < dblList.Count; i++)
{
dblSum += dblList[i];
}
return (T)Convert.ChangeType((dblSum / dblList.Count), typeof(T));
}
else
{
return default;
}
}
public static int Average(this IEnumerable<Person> people)
{
int intSum = 0;
if (people != null && people is List<Person> perList && perList.Count > 0)
{
for (int i = 0; i < perList.Count; i++)
{
intSum += perList[i].Sallary;
}
return intSum / perList.Count;
}
else
{
return default;
// throw new ArgumentNullException("Err");
}
}
}
Please note: I am not sure the type of Sallary as this wasn't provided in your post. You may need to change the Average routine (Person) slightly to adjust to your Sallary type.

We can leverage on generic types in c# to find the average. This allows us to use only one method to calculate for both integers and double.
public static double Average<T>(this List<T> source)
{
IList<T> list = source as IList<T>;
if (source == null)
throw new ArgumentNullException("Err");
if(source.GetType() == typeof(List<int>) || source.GetType() == typeof(List<double>))
{
double sum = 0;
for (int i = 0; i < list.Count; i++)
{
sum += Convert.ToDouble((object)list[i]);
}
return sum / list.Count;
}
else
{
throw new InvalidOperationException("Not possible to find average");
}
}
And to call the method
var integers = new List<int> { 5, 76, 3, 93, 143, 5, 11, 67, 5 };
var doubles = new List<double> { 1.23, 68.256, 44.55, 96.127, 393.4567, 2.45, 4.1 };
Console.WriteLine(doubles.Average());
Console.WriteLine(integers.Average());

Related

Issue with divisors finding function. Expected is <System.Int32[2]>

I have an issue with the following one :
Create a function named divisors/Divisors that takes an integer and returns an array with all of the integer's divisors(except for 1 and the number itself). If the number is prime return the string '(integer) is prime' (null in C#) (use Either String a in Haskell and Result, String> in Rust).
My code:
static int[] divisors(int a)
{
int[] array = new int[a];
int x = 0;
for( int i =2; i<a; i++)
{
if(a % i == 0)
{
array[x] = i;
x++;
}
}
if(array.Length == 0)
{
return null;
}
else
{
return array;
}
}
When I try to run it, it throws :
"Expected is <System.Int32[2]>, actual is <System.Int32[15]>
Values differ at index [2]
Extra: < 0, 0, 0... >"
Not sure what to do with this one.
I'd really appreciate some help.
The sollution :
using System.Collections.Generic;
public class Kata
{
public static int[] Divisors(int n)
{
List<int> numbers = new List<int>();
for (int i = 2; i < n; i++)
{
if (n % i == 0)
{
numbers.Add (i);
}
}
if (numbers.Count == 0)
{
return null;
}
else
{
int[] array = new int[numbers.Count];
array =numbers.ToArray();
return array;
}
}
}
I did not get that error with your code; however, your function will not return null because you have determined the Length of your array as a. So the length will never be zero. You get all those zeros because value types initialize for you. Your int array filled up with zeros. I think this excercise should prove to you that a different collection type would be more suited to data that needs to be dynamicly resized but if you are required to stick to arrays, here is some code that does.
static int[] divisors(int a)
{
int x = 0;
int[] array = new int[x];
for (int i = 2; i < a; i++)
{
if (a % i == 0)
{
x++;
Array.Resize<int>(ref array, x);
array[x-1] = i;
}
}
if (array.Length == 0)
return null;
else
return array;
}
private void button1_Click(object sender, EventArgs e)
{
int b = Int32.Parse(textBox1.Text);
int[] a = divisors(b);
if (a == null)
MessageBox.Show($"{b} is a prime number.");
else
{
foreach (int x in a)
{
Debug.Print(x.ToString());
}
}
}

Find two sum function in c#

I am trying to solve a problem in testdome online exam.
the question is 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.
here is my code , it is just 75% true and the 25% to time is exceed
using System;
using System.Linq;
using System.Collections.Generic;
class TwoSum
{
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var result = from n1 in list
from n2 in list
where n1 + n2 == sum
select new Tuple<int, int>(list.IndexOf(n1), list.IndexOf(n2));
return result.FirstOrDefault();
}
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);
}
}
you can copy paste my code in the online website and see the result.
can any one help me so we get 100% true. :D
https://www.testdome.com/Questions/Csharp/TwoSum/4318
A little bit modification from Atif's solution which we don't need to copy the list to HashSet firstly.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
HashSet<int> hs = new HashSet<int>();
for (int i = 0; i < list.Count; i++)
{
var needed = sum - list[i];
if (hs.Contains(needed))
{
return Tuple.Create(list.IndexOf(needed), i);
}
hs.Add(list[i]);
}
return null;
}
This is one of those cases where you need to come at the problem from a different approach. Instead of doing a cross join of all the values and finding the first sum that matches, instead you want to make a lookup of all the values and loop through and check if the difference of the current item and the sum are in that lookup. That way you get a worst case of linear performance instead of polynomial.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var lookup = list.Select((x, i) => new { Index = i, Value = x })
.ToLookup(x => x.Value, x => x.Index);
for (int i = 0; i < list.Count; i++)
{
int diff = sum - list[i];
if (lookup.Contains(diff))
return Tuple.Create(i, lookup[diff].First());
}
return null;
}
A slight modification to your code by using a HashSet instead of a LookUp.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var hs = new HashSet<int>();
list.ToList().ForEach(x => hs.Add(x));
for (int i = 0; i < hs.Count; i++)
{
var diff = sum - list[i];
if (hs.Contains(diff))
{
var index = list.IndexOf(diff);
return new Tuple<int, int>(i, index);
}
}
return null;
}
I have tried and tested and get 100%, i.e. all tests pass including the
"Performance test with a large number of elements" test
public static Tuple<int, int> FindTwoSum(IList<int> list, int target)
{
var dict = new Dictionary<int, int>();
for (int i = 0; i < list.Count; i++)
{
var diff = target - list[i];
int j = -1;
if(dict.TryGetValue(diff, out j))
{
return Tuple.Create<int, int>(j, i);
}
dict[list[i]] = i;
}
return null;
}
This is my working solution:
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var dictionary = new Dictionary<int, int>();
for (var i = 0; i < list.Count; i++)
{
var aim = sum - list[i];
if(dictionary.ContainsKey(aim))
{
return new Tuple<int, int> (dictionary[aim], i);
}
else if(!dictionary.ContainsKey(list[i]))
{
dictionary.Add(list[i], i);
}
}
return null;
}
A slight modification to your version also passes the test. It is not 100% correct though. That tells you test cases on Testdome are not complete. I will leave it as an exercise as to what is wrong.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var result = from n1 in list
join n2 in list
on n1 equals sum - n2
select new Tuple<int, int>(list.IndexOf(n1), list.IndexOf(n2));
return result.FirstOrDefault(x=>x.Item1!=x.Item2);
}
a non Linq extensions method using version of juharr's code
public static Tuple<int, int> FindTwoSumImprovedNonLinq(IList<int> list, int sum)
{
for (int i = 0; i < list.Count; i++)
{
int diff = sum - list[i];
if (list.IndexOf(diff) > -1)
return Tuple.Create(i, list.IndexOf(diff));
}
return null;
}
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
int max = list.Max();
for (int i = 0; i < list.Count - 1; i++)
{
int first = list[i];
if (first + max == sum) return new Tuple<int, int>(i, list.IndexOf(max));
if (first + max < sum) continue;
for (int j = i+1; j < list.Count; j++)
{
int second = list[j];
if (sum == first + second)
{
return new Tuple<int, int>(i, j);
}
}
}
return null;
}
Here's code that passes all 4 tests. There's abuncha issues about the problem, however, that make it interesting. Basic test: iterate through a list, for each number in the list, iterate through the list and find its pair, ie that which when added together equal the target value. So it's O(n**2) algorithm. The 4th test burns that down. A big hint here, you only have to return the first matching pair. So, to solve:
double iterate through the list and return solution
special case for null list
special case for no solution found
special case for entry which when doubled equals the target: they must have a different index. eg:({5,1,3}, 10) 5+5=10, however, there must be a second 5, so this fails, where ({5,1,3,5},10) succeeds returning (0,3)
So, to kick the algorithm down to O(n), we can keep a record of what #s we've found, because we only need to keep the 1st occurrence of each one. But, we need a flexible, fast, data structure to do it. Array fails because we don't know what size it will be at compile time. I tried List. So you have 10million ones, it saves the first list[0]=1, and charges on. Next is 2, 2+1!=10, add 2 to list, move on. Works.
until you have an input of 10million sequential ints, and the list is huge. So switch to Dictionary. Now it passes all 4 tests.
So, sequence through input list, for each item, search its pair in the dictionary. If not, search this item in dictionary, if not, add it. When you do find its pair in the dictionary, set your return and go.
public class Item
{
public Item(int _val, int _loc) {
val = _val;
loc = _loc;
}
public int val;
public int loc;
}
class TwoSum
{
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
Tuple<int, int> result = null;
Dictionary<int, Item> dictionary = new Dictionary<int, Item>();
int index = 0;
bool done = false;
do
{
int curr = list[index];
int pair = sum - list[index];
if (dictionary.ContainsKey(pair))
{
result = new Tuple<int, int>(index, dictionary[pair].loc);
done = true;
}
else
{
if (! dictionary.ContainsKey(curr))
{
Item found1 = new Item(curr, index);
dictionary.Add(curr, found1);
}
}
index++;
}
while (index < list.Count && !done);
return result;
}
A even simpler way is:
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
for (int i = 0; i < list.Count; i++)
{
// subtract the item to the sum to find the difference
int diff = sum - list[i];
// if that number exist in that list find its index
if (list.Contains(diff))
{
return Tuple.Create(i, list.IndexOf(diff));
}
}
return null;
}
That way you wouldn't need to lookup the entire list in advance, it still is a 75% though.
int[] arr = new int[] { 1, 0, 2, 3, 4, 3 };
for (int i = 0; i < arr.Length; i++)
{
var requiredElements = arr.Select((item, index) => new { index, item }).Where(ind => ind.item.Equals(4 - arr[i])).ToList();
if (requiredElements.Count > 0)
{
foreach (var disp in requiredElements)
Console.WriteLine("Indexes are " + i.ToString() + ":" + disp.index);
}
break;
}
}
// Where 4 is the target into - ind.item.Equals(4 - arr[i])
Here is my solution. As far as I test, It returns right indices. But I don't know if it is efficient for performance.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
for (int i = 0; i < list.Count; i++)
{
int difference = sum - list[i];
bool isExist = list.Contains(difference);
if (!isExist)
{
continue;
}
else if (difference == list[i] && list.Where(x => x == difference).ToList().Count > 1)
{
var duplicated = list.Select((item, index) => new { Value = item, Index = index }).Where(x => x.Value == difference).Take(2).ToList();
return new Tuple<int, int>(duplicated[0].Index, duplicated[1].Index);
}
else if (difference == list[i] && list.Where(x => x == difference).ToList().Count == 1) continue;
else
{
return new Tuple<int, int>(i, list.IndexOf(difference));
}
}
return null;
}
Edit:
My first solution has a huge performance problem. So I decided to improve Mohammed Turshan's solution. I think it has duplication bug. I solved that problem by using Dictionary class.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
Dictionary<int, int> dict = list.Select((value, index) =>
new { Value = value, Index = index }).ToDictionary(x => x.Index, x => x.Value);
var result = from n1 in dict
from n2 in dict
where n1.Value + n2.Value == sum && n1.Key != n2.Key
select new Tuple<int, int>(n1.Key, n2.Key);
return result.FirstOrDefault();
}
As far as I'm concerned, building a lookup table is just extra memory and overhead. In addition, it processes every item in the list rather than stopping when a match is found.
So why not just something like this?
public Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
for (int i = 0; i < list.Count; i++)
{
for (int j = i + 1; j < list.Count; j++)
{
if (list[i] + list[j] == sum)
return new Tuple<int, int>(list[i], list[j]);
}
}
return null;
}
Maybe someone needs Java Solution
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> numAndIndex = new HashMap<>();
for(int currentIndex=0; currentIndex<nums.length; currentIndex++){
int currentNumber=nums[currentIndex];
Integer expectedIndex=numAndIndex.get(target-currentNumber);
if(expectedIndex!=null){
return new int[]{expectedIndex, currentIndex};
}
numAndIndex.put(currentNumber, currentIndex);
}
return null;
}
}
public static Tuple FindTwoSum(IList list, int sum)
{
for(int i=0;i<list.Count;i++)
{
for(int j=0;j<list.Count;j++)
{
if((list[i]+list[j])==12)
{
return new Tuple<int, int>(i,j);
}
}
}
return null;
}
This will work

Calculating the Power set of large string array in C# [duplicate]

This question already has answers here:
Memory efficient power set algorithm
(5 answers)
Closed 6 years ago.
I want to calculate power set of string array (consider it as a set). When I am exceeding above 26 elements it is thowing out of memory exception.
List<int> ff = new List<int>();
double length = Math.Pow(2, 29);
for (int i = 0; i < length; i++)
{
ff.Add(1);
}
Above code will produce the that exception if you run it. The size of the set may go up to 1000. So the size of power set of that set will be 2^1000.
How can I deal with this?
EDIT:
I know that above code is not a function of power set. I was just checking how big array c# will be able to hold.
private static Dictionary<int, object> PowerSetB(string[] input)
{
int n = input.Length;
// Power set contains 2^N subsets.
int powerSetCount = 1 << n;
var ans = new Dictionary<int, object>();
for (int setMask = 0; setMask < powerSetCount; setMask++)
{
var s = new ArrayList();
for (int i = 0; i < n; i++)
{
// Checking whether i'th element of input collection should go to the current subset.
if ((setMask & (1 << i)) > 0)
s.Add(input[i]);
}
ans[setMask] = s;
}
return ans;
}
Above code is my function of power set.
Thank you in advance.
Do you really want to store all the items in memory? I suggest using IEnumerable<int> instead of materialized List<int>:
// just enumeration, coefficients aren't stored
public static IEnumerable<int> Serie(Func<int, int> coefByIndex) {
if (null == coefByIndex)
throw new ArgumentNullException("coefByIndex");
for (int i = 0; ; ++i)
yield return coefByIndex(i);
}
// Let's sum up all 2**29 values,
// i.e. compute f(1) summing up 2**29 items (it's a long process...)
// sum = 1.44115187606094E+17 (diverges, as we might have expected)
Double sum = Serie(index => index)
.Select(x => x * 1.0)
.Take(1 << 29)
.Sum();
Edit: Once agian, do not materialize (Dictionary<int, object>) huge results! Provide an IReadOnlyDictionary<int, int[]> interface but not implementation as Dictionary<int, object>,
Something like this:
// ArrayList is an obsolete collection;
// int[] far more natural here
public sealed class PowerSet: IReadOnlyDictionary<int, int[]> {
private int m_Power;
private int[] getItem(int index) {
int[] result = new int[m_Power];
for (int i = 0; i < m_Power; ++i) {
result[i] = index % 2;
index /= 2;
}
return result;
}
public PowerSet(int power) {
m_Power = power;
}
public int[] this[int key] {
get {
if (key >= 0 && key < Count)
return getItem(key);
else
throw new ArgumentOutOfRangeException("key");
}
}
public int Count {
get {
return 1 << m_Power;
}
}
public IEnumerable<int> Keys {
get {
return Enumerable.Range(0, Count);
}
}
public IEnumerable<int[]> Values {
get {
return Enumerable.Range(0, Count).Select(index => getItem(index));
}
}
public bool ContainsKey(int key) {
return key >= 0 && key < Count;
}
public IEnumerator<KeyValuePair<int, int[]>> GetEnumerator() {
return Enumerable
.Range(0, Count)
.Select(index => new KeyValuePair<int, int[]>(index, getItem(index)))
.GetEnumerator();
}
public bool TryGetValue(int key, out int[] value) {
if (key >= 0 && key < Count) {
value = getItem(key);
return true;
}
value = null;
return false;
}
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
}
...
// Just an easy call
private static IDictionary<int, int[]> PowerSetB(string[] input) {
return new PowerSet(input.Length);
}

c# permutation without repetition when order is important [duplicate]

I have a list of Offers, from which I want to create "chains" (e.g. permutations) with limited chain lengths.
I've gotten as far as creating the permutations using the Kw.Combinatorics project.
However, the default behavior creates permutations in the length of the list count. I'm not sure how to limit the chain lengths to 'n'.
Here's my current code:
private static List<List<Offers>> GetPerms(List<Offers> list, int chainLength)
{
List<List<Offers>> response = new List<List<Offers>>();
foreach (var row in new Permutation(list.Count).GetRows())
{
List<Offers> innerList = new List<Offers>();
foreach (var mix in Permutation.Permute(row, list))
{
innerList.Add(mix);
}
response.Add(innerList);
innerList = new List<Offers>();
}
return response;
}
Implemented by:
List<List<AdServer.Offers>> lst = GetPerms(offers, 2);
I'm not locked in KWCombinatorics if someone has a better solution to offer.
Here's another implementation which I think should be faster than the accepted answer (and it's definitely less code).
public static IEnumerable<IEnumerable<T>> GetVariationsWithoutDuplicates<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items.Distinct()
from permutation in GetVariationsWithoutDuplicates(items.Where(i => !EqualityComparer<T>.Default.Equals(i, item)).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<IEnumerable<T>> GetVariations<T>(IList<T> items, int length)
{
if (length == 0 || !items.Any()) return new List<List<T>> { new List<T>() };
return from item in items
from permutation in GetVariations(Remove(item, items).ToList(), length - 1)
select Prepend(item, permutation);
}
public static IEnumerable<T> Prepend<T>(T first, IEnumerable<T> rest)
{
yield return first;
foreach (var item in rest) yield return item;
}
public static IEnumerable<T> Remove<T>(T item, IEnumerable<T> from)
{
var isRemoved = false;
foreach (var i in from)
{
if (!EqualityComparer<T>.Default.Equals(item, i) || isRemoved) yield return i;
else isRemoved = true;
}
}
On my 3.1 GHz Core 2 Duo, I tested with this:
public static void Test(Func<IList<int>, int, IEnumerable<IEnumerable<int>>> getVariations)
{
var max = 11;
var timer = System.Diagnostics.Stopwatch.StartNew();
for (int i = 1; i < max; ++i)
for (int j = 1; j < i; ++j)
getVariations(MakeList(i), j).Count();
timer.Stop();
Console.WriteLine("{0,40}{1} ms", getVariations.Method.Name, timer.ElapsedMilliseconds);
}
// Make a list that repeats to guarantee we have duplicates
public static IList<int> MakeList(int size)
{
return Enumerable.Range(0, size/2).Concat(Enumerable.Range(0, size - size/2)).ToList();
}
Unoptimized
GetVariations 11894 ms
GetVariationsWithoutDuplicates 9 ms
OtherAnswerGetVariations 22485 ms
OtherAnswerGetVariationsWithDuplicates 243415 ms
With compiler optimizations
GetVariations 9667 ms
GetVariationsWithoutDuplicates 8 ms
OtherAnswerGetVariations 19739 ms
OtherAnswerGetVariationsWithDuplicates 228802 ms
You're not looking for a permutation, but for a variation. Here is a possible algorithm. I prefer iterator methods for functions that can potentially return very many elements. This way, the caller can decide if he really needs all elements:
IEnumerable<IList<T>> GetVariations<T>(IList<T> offers, int length)
{
var startIndices = new int[length];
var variationElements = new HashSet<T>(); //for duplicate detection
while (startIndices[0] < offers.Count)
{
var variation = new List<T>(length);
var valid = true;
for (int i = 0; i < length; ++i)
{
var element = offers[startIndices[i]];
if (variationElements.Contains(element))
{
valid = false;
break;
}
variation.Add(element);
variationElements.Add(element);
}
if (valid)
yield return variation;
//Count up the indices
startIndices[length - 1]++;
for (int i = length - 1; i > 0; --i)
{
if (startIndices[i] >= offers.Count)
{
startIndices[i] = 0;
startIndices[i - 1]++;
}
else
break;
}
variationElements.Clear();
}
}
The idea for this algorithm is to use a number in offers.Count base. For three offers, all digits are in the range 0-2. We then basically increment this number step by step and return the offers that reside at the specified indices. If you want to allow duplicates, you can remove the check and the HashSet<T>.
Update
Here is an optimized variant that does the duplicate check on the index level. In my tests it is a lot faster than the previous variant:
IEnumerable<IList<T>> GetVariations<T>(IList<T> offers, int length)
{
var startIndices = new int[length];
for (int i = 0; i < length; ++i)
startIndices[i] = i;
var indices = new HashSet<int>(); // for duplicate check
while (startIndices[0] < offers.Count)
{
var variation = new List<T>(length);
for (int i = 0; i < length; ++i)
{
variation.Add(offers[startIndices[i]]);
}
yield return variation;
//Count up the indices
AddOne(startIndices, length - 1, offers.Count - 1);
//duplicate check
var check = true;
while (check)
{
indices.Clear();
for (int i = 0; i <= length; ++i)
{
if (i == length)
{
check = false;
break;
}
if (indices.Contains(startIndices[i]))
{
var unchangedUpTo = AddOne(startIndices, i, offers.Count - 1);
indices.Clear();
for (int j = 0; j <= unchangedUpTo; ++j )
{
indices.Add(startIndices[j]);
}
int nextIndex = 0;
for(int j = unchangedUpTo + 1; j < length; ++j)
{
while (indices.Contains(nextIndex))
nextIndex++;
startIndices[j] = nextIndex++;
}
break;
}
indices.Add(startIndices[i]);
}
}
}
}
int AddOne(int[] indices, int position, int maxElement)
{
//returns the index of the last element that has not been changed
indices[position]++;
for (int i = position; i > 0; --i)
{
if (indices[i] > maxElement)
{
indices[i] = 0;
indices[i - 1]++;
}
else
return i;
}
return 0;
}
If I got you correct here is what you need
this will create permutations based on the specified chain limit
public static List<List<T>> GetPerms<T>(List<T> list, int chainLimit)
{
if (list.Count() == 1)
return new List<List<T>> { list };
return list
.Select((outer, outerIndex) =>
GetPerms(list.Where((inner, innerIndex) => innerIndex != outerIndex).ToList(), chainLimit)
.Select(perms => (new List<T> { outer }).Union(perms).Take(chainLimit)))
.SelectMany<IEnumerable<IEnumerable<T>>, List<T>>(sub => sub.Select<IEnumerable<T>, List<T>>(s => s.ToList()))
.Distinct(new PermComparer<T>()).ToList();
}
class PermComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> x, List<T> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<T> obj)
{
return (int)obj.Average(o => o.GetHashCode());
}
}
and you'll call it like this
List<List<AdServer.Offers>> lst = GetPerms<AdServer.Offers>(offers, 2);
I made this function is pretty generic so you may use it for other purpose too
eg
List<string> list = new List<string>(new[] { "apple", "banana", "orange", "cherry" });
List<List<string>> perms = GetPerms<string>(list, 2);
result

break a collection up into smaller collections, but repeat items

I can't get my head around how to do this.
I have a collection of objects
{ object1, object2, object3, object4 }
I want to break up this collection into a collection of collections, so that I end up with something that looks like
{ { object1, object2}, {object2, object3}, {object3, object4} }
I've found how to chunk the collection into smaller ones, but it is the repeating of the previous item in each collection that is doing my head in.
Any help greatly appreciated!
My current chunk method (taken from another question on here) is
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int size)
{
return source.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / size)
.Select(x => x.Select(v => v.Value));
}
EDIT
This works, but is there a better way?
public static ICollection<ICollection<T>> BreakUp<T>(this IEnumerable<T> polylines, int size)
{
var results = new Collection<ICollection<T>>();
results.Add(new Collection<T>());
var x = 0;
for (var i = 0; i < polylines.Count(); i++)
{
results[x].Add(polylines.ElementAt(i));
if (results[x].Count() % size == 0 && i != polylines.Count() - 1)
{
x++;
results.Add(new Collection<T>());
results[x].Add(polylines.ElementAt(i));
}
}
return results;
}
You can simplify your code like this:
public static IEnumerable<IEnumerable<T>> BreakUp<T>(IEnumerable<T> this source, int size)
{
var max = source.Count();
int i = 0;
while (i < max)
{
var current = source.Skip(i).Take(size);
if (current.Count() > 1)
yield return current;
i += size -1;
}
}
Test:
void Main()
{
Console.WriteLine("Example 1");
var source = new Int32[] {1, 2, 3, 4, 5};
foreach (var i in BreakUp(source, 2))
Console.WriteLine(i);
Console.WriteLine("Example 2");
foreach (var i in BreakUp(source, 4))
Console.WriteLine(i);
}
Here's a solution that iterates source only once:
public static IEnumerable<IEnumerable<T>> BreakUp<T>(IEnumerable<T> this source, int size)
{
using(var e = source.GetEnumerator())
{
T last = default(T);
bool has_last = false;
while(e.MoveNext())
{
var current = new List<T>(size);
if(has_last)
current.Add(last);
last = (T)e.Current;
current.Add(last);
while(current.Count < size && e.MoveNext())
{
last = (T)e.Current;
current.Add(last);
has_last = true;
}
yield return current;
}
}
}
Results:
If you only need to group like this
{ { object1, object2}, {object2, object3}, {object3, object4} }
then following code would suffice
return source.Zip(source.Skip(1), (o1, o2) => new List<T> { o1, o2 });
EDIT:
Solution for a variable number of elements:
{ { object1, object2, object3}, {object2, object3, object4}, {object3, object4, object5} }
source.TakeWhile((o,i) => i <= source.Count() - size)
.Select((o,i) => source.Where((lo,li) => li >= i && li < i + size));
This may not be as concise as other solutions, but it iterates through source only once.
public static IEnumerable<List<T>> BreakUp<T>(this IEnumerable<T> source, int size)
{
var max = source.Count();
int start = 0;
var enumerator = source.GetEnumerator();
enumerator.MoveNext();
// We use "max - 1" instead of "max" to avoid adding a list of length 1
while (start < max - 1)
{
int current = 0;
List<T> list = new List<T>();
list.Add(enumerator.Current);
current++;
while(current < size && enumerator.MoveNext())
{
list.Add(enumerator.Current);
current++;
}
yield return list;
start += size - 1;
}
}

Categories

Resources