I want to create an extension method like this
public static bool AllConsecutives(this IEnumerable<int> intValues )
This method should return true if all items in the list are consecutive (with no gaps)
some test cases
(new List<int>() {2, 3, 4, 5, 6}).AllConsecutives() == true
(new List<int>() {3, 7, 4, 5, 6}).AllConsecutives() == true //as it is not sensitive to list order
(new List<int>() {2, 3, 4, 7, 6}).AllConsecutives() == false //as the five is missing
int expected = intValues.Min();
foreach(int actual in intValues.OrderBy(x => x))
{
if (actual != expected++)
return false;
}
return true;
You can also verify, that collection has at least one item, before executing Min. Or you can sort items prior to taking min (in this case it will be first one, or will not be any, if collection is empty). Also in this case you will save one iteration for finding minimal value:
var sortedValues = intValues.OrderBy(x => x);
int expected = sortedValues.FirstOrDefault();
foreach (int actual in sortedValues)
{
if (actual != expected++)
return false;
}
return true;
Tried and seems to work with the given examples
public static bool AllConsecutives(this IEnumerable<int> intValues )
{
var ord = intValues.OrderBy(i => i);
int curV = ord.Min();
foreach(int x in ord)
{
if(x != curV)
return false;
curV++;
}
return true;
}
The list is consecutive if it does not contains duplicates and the difference between the max. and min. values is equal to the number of items in the list minus one, so:
public static bool AllConsecutives(this IEnumerable<int> intValues)
{
int minValue = Int32.MaxValue;
int maxValue = Int32.MinValue;
int count = 0;
HashSet<int> values = new HashSet<int>();
foreach (int intValue in intValues) {
if (values.Contains(intValue))
return false;
values.Add(intValue);
if (intValue > maxValue)
maxValue = intValue;
if (intValue < minValue)
minValue = intValue;
count++;
}
return (count == 0) || (maxValue-minValue+1 == count);
}
Error checking and using Linq:
public static class myExtension
{
public static bool AllConsecutives(this IEnumerable<int> targetList)
{
bool result = false;
if ((targetList != null) && (targetList.Any ()))
{
var ordered = targetList.OrderBy (l => l);
int first = ordered.First ();
result = ordered.All (item => item == first++);
}
return result;
}
}
// tested with
void Main()
{
Console.WriteLine ( (new List<int>() {2, 3, 4, 5, 6}).AllConsecutives() ); // true
Console.WriteLine ( (new List<int>() {3, 7, 4, 5, 6}).AllConsecutives() ); // true //as it is not sensitive to list order
Console.WriteLine ( (new List<int>() {2, 3, 4, 7, 6}).AllConsecutives() ); // false //as the five is missing
}
Something like this:
if (intValues.Count() <= 1)
return true;
var ordered = intValues.OrderBy(i => i).ToList();
return (ordered.First() + ordered.Count() - 1) == ordered.Last();
list.Sort();
return !list.Skip(1).Where((i, j) => (i != (list[j] + 1))).Any();
Another possible solution that doesn't requires sorting, is to use hashset, and while building the hashset you can hold the min value. With this the run time will be O(n).
This will not take care of duplicate values which you can just add a check while building the hashset and see if the hashset already contains the value.
HashSet<int> hash = new HashSet<int>();
int minValue = int.MaxValue;
foreach(int i in list)
{
if(minValue > i)
minValue = i;
hash.Add(i);
}
for(int count = 1; count < list.Count; ++count)
{
if(!hash.Contains(++minValue))
return false;
}
return true;
Related
How can I display only 3 consecutive numbers for example in my code below I only want it to return 4, as that appears 3 times.
9 is 4 times so do not want that and 7 is twice so not what want that.
The code I currently have display 9
int[] intArray = { 9, 9, 9, 9, 6, 4, 4, 4, 7, 7 };
var adjacentDuplicateNumbers = intArray
.Skip(1)
.Where((value, index) => value == intArray[index])
.Distinct();
var enumerable = adjacentDuplicateNumbers as int[] ?? adjacentDuplicateNumbers.ToArray();
if (enumerable.Any())
{
Console.WriteLine("{0} is a consecutive number and is repeated 3 times.", enumerable.First());
}
else
{
Console.WriteLine("no consecutive number found.");
}
Using the extension method of this post: LINQ to find series of consecutive numbers
public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> seq, Func<T, T, bool> condition)
{
T prev = seq.First();
List<T> list = new List<T>() { prev };
foreach (T item in seq.Skip(1))
{
if (condition(prev, item) == false)
{
yield return list;
list = new List<T>();
}
list.Add(item);
prev = item;
}
yield return list;
}
Usage:
var res = intArray.GroupWhile((a, b) => a == b).
Where(x => x.Count() == 3).Select(x => x.First());
Sometimes a simple foor loop is enough (and should be faster than linq)
int[] intArray = { 9, 9, 9, 9, 6, 4, 4, 4, 7, 7 };
var minus2 = intArray[0];
var minus1 = intArray[1];
var result = new List<int>();
for(int i = 2; i < intArray.Length; i++)
{
var current = intArray[i];
if(minus2 == minus1 && minus1 == current)
{
result.Add(current);
}
minus2 = minus1;
minus1 = current;
}
var results = intArray.Distinct()
.ToDictionary(k => k, v => intArray.Count(x => x == v))
.Where(x => x.Value == 3)
.Select(x => x.Key);
Take the district elements in the array. Use these as keys in a dictionary that map to the number of occurrences of this key in the original array. Use Where to only select pairs that match the required count (3). Use Select to return the resulting keys - in this example only 4.
There are lots and lots of questions on SO about finding if one list is the subset of another list.
i.e. bool isSubset = !t2.Except(t1).Any();
I can't seem to find one that accounts for order
as in given a sequence:
1,1,2,5,8,1,9,1,2
The subsequences...
2,5,8,1,9 true
1,2,5,8,1 true
5,2,1 false
1,2,5,1,8 false
1,1,2 true
1,1,1,2 false
A list in which the order is significant is a generalisation of the concept of string. Therefore you want to use a substring-finding algorithm.
There are several possibilities, but Knuth–Morris–Pratt is a good choice. It has some initial Θ(m) overhead where m is the length of the sublist sought, and then finds in Θ(n) where n is the distance to the sublist sought, or the length of the whole list if it isn't there. This beats the simple item-by-item compare which is Θ((n-m+1) m):
public static class ListSearching
{
public static bool Contains<T>(this IList<T> haystack, IList<T> needle)
{
return Contains(haystack, needle, null);
}
public static bool Contains<T>(this IList<T> haystack, IList<T> needle, IEqualityComparer<T> cmp)
{
return haystack.IndexOf(needle, cmp) != -1;
}
public static int IndexOf<T>(this IList<T> haystack, IList<T> needle)
{
return IndexOf(haystack, needle, null);
}
public static int IndexOf<T>(this IList<T> haystack, IList<T> needle, IEqualityComparer<T> cmp)
{
if(haystack == null || needle == null)
throw new ArgumentNullException();
int needleCount = needle.Count;
if(needleCount == 0)
return 0;//empty lists are everywhere!
if(cmp == null)
cmp = EqualityComparer<T>.Default;
int count = haystack.Count;
if(needleCount == 1)//can't beat just spinning through for it
{
T item = needle[0];
for(int idx = 0; idx != count; ++idx)
if(cmp.Equals(haystack[idx], item))
return idx;
return -1;
}
int m = 0;
int i = 0;
int[] table = KMPTable(needle, cmp);
while(m + i < count)
{
if(cmp.Equals(needle[i], haystack[m + i]))
{
if(i == needleCount - 1)
return m == needleCount ? -1 : m;//match -1 = failure to find conventional in .NET
++i;
}
else
{
m = m + i - table[i];
i = table[i] > -1 ? table[i] : 0;
}
}
return -1;
}
private static int[] KMPTable<T>(IList<T> sought, IEqualityComparer<T> cmp)
{
int[] table = new int[sought.Count];
int pos = 2;
int cnd = 0;
table[0] = -1;
table[1] = 0;
while(pos < table.Length)
if(cmp.Equals(sought[pos - 1], sought[cnd]))
table[pos++] = ++cnd;
else if(cnd > 0)
cnd = table[cnd];
else
table[pos++] = 0;
return table;
}
}
Testing this:
var list = new[]{ 1, 1, 2, 5, 8, 1, 9, 1, 2 };
Console.WriteLine(list.Contains(new[]{2,5,8,1,9})); // True
Console.WriteLine(list.Contains(new[]{1,2,5,8,1})); // True
Console.WriteLine(list.Contains(new[]{5,2,1})); // False
Console.WriteLine(list.Contains(new[]{1,2,5,1,8})); // False
Console.WriteLine(list.Contains(new[]{1,1,2})); // True
Console.WriteLine(list.Contains(new[]{1,1,1,2})); // False
Unfortunately there is no such function in .net. You need Knuth–Morris–Pratt algo for it. One guy already implemented it as linq extension https://code.google.com/p/linq-extensions/
This works for me:
var source = new [] { 1,1,2,5,8,1,9,1,2 };
Func<int[], int[], bool> contains =
(xs, ys) =>
Enumerable
.Range(0, xs.Length)
.Where(n => xs.Skip(n).Take(ys.Length).SequenceEqual(ys))
.Any();
Console.WriteLine(contains(source, new [] { 2,5,8,1,9 })); // true
Console.WriteLine(contains(source, new [] { 1,2,5,8,1 })); // true
Console.WriteLine(contains(source, new [] { 5,2,1 })); // false
Console.WriteLine(contains(source, new [] { 1,2,5,1,8 })); // false
Console.WriteLine(contains(source, new [] { 1,1,2 })); // true
Console.WriteLine(contains(source, new [] { 1,1,1,2 })); // false
there is a workaround to the limitation. You can change the enumerable to a string and then make use of the Contains method.
var t1 = new List<int> {1, 1, 2, 5, 8, 1, 9, 1, 2};
var t2 = new List<int> {2,5,8,1,9};
var t3 = new List<int> {5,2,1};
var t1Str = String.Join(",", t1);
t1Str.Contains(String.Join(",", t2););//true
t1Str.Contains(String.Join(",", t3););//false
You can build your own extension, I wrote a simple IsSubset method:
Console App for testing:
class Program
{
static void Main(string[] args)
{
var list = new List<int> { 1, 3, 5, 2, 4, 6 };
var subList = new List<int> { 3, 5};
var subList2 = new List<int> { 1, 4 };
bool isSublist1 = subList.IsSubset(list);
bool isSublist2 = subList2.IsSubset(list);
Console.WriteLine(isSublist1 + "; " + isSublist2);
/* True; False */
Console.ReadKey();
}
}
IEnumerable Extension:
public static class IEnumerableExtensions
{
public static bool IsSubset<T>(this IEnumerable<T> subsetEnumerable, IEnumerable<T> enumerable)
{
var found = false;
var list = enumerable as IList<T> ?? enumerable.ToList();
var listCount = list.Count();
var subsetList = subsetEnumerable as IList<T> ?? subsetEnumerable.ToList();
var posListCount = subsetList.Count();
/* If the SubList is bigger, it can't be a sublist */
if (listCount < posListCount) {
return false;
}
/* find all indexes of the first item of the sublist in the list */
var firstElement = subsetList.First();
var indexes = new List<int>();
var index = 0;
foreach (var elem in list)
{
if (elem.Equals(firstElement))
{
indexes.Add(index);
}
index++;
}
/* check all first item founds for the subsequence */
foreach (var i in indexes)
{
int x=0;
for (x = 0; x < posListCount && (i + x) < listCount; x++)
{
if (!Equals(subsetList[x], list[(i + x)]))
{
found = false;
break;
}
found = true;
}
if (x + 1 < posListCount)
found = false;
}
return found;
}
}
May be using join can get you what you want. Join will return the matching records. If record count is greater than 0 than there is a match else no match.
Below I have explained through a sample code:
class Program
{
static void Main(string[] args)
{
List<Employee> empList = new List<Employee>
{
new Employee{EmpID = 1},
new Employee{EmpID = 1},
new Employee{EmpID = 2},
new Employee{EmpID = 5},
new Employee{EmpID = 8},
new Employee{EmpID = 1},
new Employee{EmpID = 9},
new Employee{EmpID = 1},
new Employee{EmpID = 2}
};
List<Manager> mgrList = new List<Manager>
{
new Manager{ManagerID = 7},
new Manager{ManagerID = 3},
new Manager{ManagerID = 6}
};
var result = (from emp in empList
join mgr in mgrList on emp.EmpID equals mgr.ManagerID
select new { emp.EmpID}).Count();
Console.WriteLine(result);
Console.ReadKey();
}
}
public class Employee
{
public int EmpID { get; set; }
}
public class Manager
{
public int ManagerID { get; set; }
}
I have two lists of the same type. That type does not have an identifier or any other guaranteed way to programatically distinguish.
List A: {1, 2, 2, 3, 5, 8, 8, 8}
List B: {1, 3, 5, 8}
I want the items from A that are not in B.
Desired Result: {2, 2, 8, 8}
If the types had identifiers, I could use a statement like the following...
var result = listA
.Where(a => listB.Where(b => b.Id == a.Id).Count() == 0)
.ToList();
So far, the only way I can do this is with a loop where I add each item the number of times it doesn't appear in the original list.
foreach (var val in listB.Select(b => b.val).Distinct())
{
var countA = listA.Where(a => a.val == val).Count();
var countB = listB.Where(b => b.val == val).Count();
var item = listA.Where(a => a.val == val).FirstOrDefault();
for (int i=0; i<countA-countB; i++)
result.Add(item);
}
Is there a cleaner way to achieve this?
EDIT:
Here is a simplified version of the object in the lists. It's coming from a Web service that's hitting another system.
public class myObject
{
public DateTime SomeDate { get; set; }
public decimal SomeNumber; { get; set; }
public bool IsSomething { get; set; }
public string SomeString { get; set; }
}
The data I am receiving has the same values for SomeDate/SomeString and repeated values for SomeNumber and IsSomething. Two objects might have equal properties, but I need to treat them as distinct objects.
try this:
var listA = new List<Int32> {1, 2, 2, 3, 5, 8, 8, 8};
var listB = new List<Int32> {1, 3, 5, 8};
var listResult = new List<Int32>(listA);
foreach(var itemB in listB)
{
listResult.Remove(itemB);
}
What am I missing?
class Program
{
static void Main(string[] args)
{
List<int> a = new List<int>();
a.Add(1);
a.Add(2);
a.Add(2);
a.Add(3);
a.Add(5);
a.Add(8);
a.Add(8);
a.Add(8);
List<int> b = new List<int>();
b.Add(1);
b.Add(3);
b.Add(5);
b.Add(8);
foreach (int x in b)
a.Remove(x);
foreach (int x in a)
Console.WriteLine(x);
Console.ReadKey(false);
}
}
Are the objects same instances in both lists? If so you can use .Where(a => listB.Where(b => b == a).Count() == 0)
Or
.Where(a => !listB.Any(b => b == a))
You could sort both lists and then iterate through them both at the same time.
public IEnumerable<int> GetComplement(IEnumerable<int> a, IEnumerable<int> b)
{
var listA = a.ToList();
listA.Sort();
var listB = b.ToList();
listB.Sort();
int i=0,j=0;
while( i < listA.Count && j < listB.Count )
{
if(listA[i] > listB[j]) {yield return listB[j];j++;}
else if (listA[i] < listB[j]) {yield return listA[i]; i++; }
else {i++;j++;}
}
while(i < listA.Count)
{
yield return listA[i];
i++;
}
while(j < listB.Count)
{
yield return listB[j];
j++;
}
}
I don't know if this is "cleaner", but it should be more performant on large sets of data.
This is a bit nasty but it does what you want. Not sure about performance though.
var a = new List<int> { 1, 2, 2, 3, 5, 8, 8, 8 };
var b = new List<int> { 1, 3, 5, 8 };
var c = from x in a.Distinct()
let a_count = a.Count(el => el == x)
let b_count = b.Count(el => el == x)
from val in Enumerable.Repeat (x, a_count - b_count)
select val;
Why don't you implement your own equality comparer for your myObject:
public class YourTypeEqualityComparer : IEqualityComparer<myObject>
{
public bool Equals(myObject x, myObject y)
public int GetHashCode(myObject obj)
}
and then use it like this:
var list1 = new List<myObj>();
var list2 = new List<myObj>()
list1.RemoveAll(i =>
list2.Contains(list1),
new YourTypeEqualityComparer()
);
now list1 contains result.
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
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;
}