Except has similar effect to Distinct? - c#

I just discovered that Except() will remove all elements in the second list from the first, but it also has the effect that it makes all elements in the returned result distinct.
Simple way around I am using is Where(v => !secondList.Contains(v))
Can anyone explain to me why this is the behavior, and if possible point me to the documentation that explains this?

The documentation for the Except function states:
Produces the set difference of two sequences by using the default equality comparer to compare values.
The set difference of two sets is defined as the members of the first set that do not appear in the second set.
The important word here is set, which is defined as:
...an abstract data structure that can store certain values, without any particular order, and no repeated values...
Because Except is documented as a set-based operation, it also has the effect of making the resulting values distinct.

You wrote:
Simple way around I am using is Where(v => !secondList.Contains(v))
When you do this, there is still Distict done with secondList.
For example:
var firstStrings = new [] { "1", null, null, null, "3", "3" };
var secondStrings = new [] { "1", "1", "1", null, null, "4" };
var resultStrings = firstStrings.Where(v => !secondStrings.Contains(v)); // 3, 3
I created an extension method to have no distinct at all. Examle of usage:
var result2Strings = firstStrings.ExceptAll(secondStrings).ToList(); // null, 3, 3
This is what it does:
This is the source:
public static IEnumerable<TSource> ExceptAll<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second)
{
// Do not call reuse the overload method because that is a slower imlementation
if (first == null) { throw new ArgumentNullException("first"); }
if (second == null) { throw new ArgumentNullException("second"); }
var secondList = second.ToList();
return first.Where(s => !secondList.Remove(s));
}
public static IEnumerable<TSource> ExceptAll<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer)
{
if (first == null) { throw new ArgumentNullException("first"); }
if (second == null) { throw new ArgumentNullException("second"); }
var comparerUsed = comparer ?? EqualityComparer<TSource>.Default;
var secondList = second.ToList();
foreach (var item in first)
{
if (secondList.Contains(item, comparerUsed))
{
secondList.Remove(item);
}
else
{
yield return item;
}
}
}
Edit: A faster implementation, based on the comment of DigEmAll
public static IEnumerable<TSource> ExceptAll<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer = null)
{
if (first == null) { throw new ArgumentNullException(nameof(first)); }
if (second == null) { throw new ArgumentNullException(nameof(second)); }
var secondCounts = new Dictionary<TSource, int>(comparer ?? EqualityComparer<TSource>.Default);
int count;
int nullCount = 0;
// Count the values from second
foreach (var item in second)
{
if (item == null)
{
nullCount++;
}
else
{
if (secondCounts.TryGetValue(item, out count))
{
secondCounts[item] = count + 1;
}
else
{
secondCounts.Add(item, 1);
}
}
}
// Yield the values from first
foreach (var item in first)
{
if (item == null)
{
nullCount--;
if (nullCount < 0)
{
yield return item;
}
}
else
{
if (secondCounts.TryGetValue(item, out count))
{
if (count == 0)
{
secondCounts.Remove(item);
yield return item;
}
else
{
secondCounts[item] = count - 1;
}
}
else
{
yield return item;
}
}
}
}
More info on my blog (also variant for Intersect and Union)

Given A = [1, 2, 2, 3, 3, 3] and B = [3].
A.Except(B); returns [1, 2] as Greg Beech explained in his response
A.ExceptAll(B); from Alex Siepman response, returns [1, 2, 2, 3, 3] (and I find the name ambiguous).
A.Where(v => !B.Contains(v)) from OP work around returns [1, 2, 2]
I suppose that OP work around is the desired behavior, and this one has not be treated.
The main issue with OP work around is that List<T>.Contains(T) is O(n) and Where is also O(n) making the solution O(n²) in time (for A and B of equivalent sizes) and O(1) in memory.
We can make it O(n) in time and O(n) in memory by using hash set:
// I accept any better name for this method
public static IEnumerable<TSource> ExceptFrom<TSource>(
IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer)
{
if (first == null)
throw new ArgumentNullException(nameof(first));
if (second == null)
throw new ArgumentNullException(nameof(second));
var secondSet = second as HashSet<TSource> ?? // this trick ignore the comparer
second.ToHashSet(comparer ?? EqualityComparer<TSource>.Default);
// Contains is O(1) for HashSet.
return first.Where(v => !secondSet.Contains(v));
}

Related

Find object index in binding list? [duplicate]

This question already has answers here:
Get List<> element position in c# using LINQ
(11 answers)
How to get the index of an element in an IEnumerable?
(12 answers)
Closed 8 years ago.
Given a datasource like that:
var c = new Car[]
{
new Car{ Color="Blue", Price=28000},
new Car{ Color="Red", Price=54000},
new Car{ Color="Pink", Price=9999},
// ..
};
How can I find the index of the first car satisfying a certain condition with LINQ?
EDIT:
I could think of something like this but it looks horrible:
int firstItem = someItems.Select((item, index) => new
{
ItemName = item.Color,
Position = index
}).Where(i => i.ItemName == "purple")
.First()
.Position;
Will it be the best to solve this with a plain old loop?
myCars.Select((v, i) => new {car = v, index = i}).First(myCondition).index;
or the slightly shorter
myCars.Select((car, index) => new {car, index}).First(myCondition).index;
or the slightly shorter shorter
myCars.Select((car, index) => (car, index)).First(myCondition).index;
Simply do :
int index = List.FindIndex(your condition);
E.g.
int index = cars.FindIndex(c => c.ID == 150);
An IEnumerable is not an ordered set.
Although most IEnumerables are ordered, some (such as Dictionary or HashSet) are not.
Therefore, LINQ does not have an IndexOf method.
However, you can write one yourself:
///<summary>Finds the index of the first item matching an expression in an enumerable.</summary>
///<param name="items">The enumerable to search.</param>
///<param name="predicate">The expression to test the items against.</param>
///<returns>The index of the first matching item, or -1 if no items match.</returns>
public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate) {
if (items == null) throw new ArgumentNullException("items");
if (predicate == null) throw new ArgumentNullException("predicate");
int retVal = 0;
foreach (var item in items) {
if (predicate(item)) return retVal;
retVal++;
}
return -1;
}
///<summary>Finds the index of the first occurrence of an item in an enumerable.</summary>
///<param name="items">The enumerable to search.</param>
///<param name="item">The item to find.</param>
///<returns>The index of the first matching item, or -1 if the item was not found.</returns>
public static int IndexOf<T>(this IEnumerable<T> items, T item) { return items.FindIndex(i => EqualityComparer<T>.Default.Equals(item, i)); }
myCars.TakeWhile(car => !myCondition(car)).Count();
It works! Think about it. The index of the first matching item equals the number of (not matching) item before it.
Story time
I too dislike the horrible standard solution you already suggested in your question. Like the accepted answer I went for a plain old loop although with a slight modification:
public static int FindIndex<T>(this IEnumerable<T> items, Predicate<T> predicate) {
int index = 0;
foreach (var item in items) {
if (predicate(item)) break;
index++;
}
return index;
}
Note that it will return the number of items instead of -1 when there is no match. But let's ignore this minor annoyance for now. In fact the horrible standard solution crashes in that case and I consider returning an index that is out-of-bounds superior.
What happens now is ReSharper telling me Loop can be converted into LINQ-expression. While most of the time the feature worsens readability, this time the result was awe-inspiring. So Kudos to the JetBrains.
Analysis
Pros
Concise
Combinable with other LINQ
Avoids newing anonymous objects
Only evaluates the enumerable until the predicate matches for the first time
Therefore I consider it optimal in time and space while remaining readable.
Cons
Not quite obvious at first
Does not return -1 when there is no match
Of course you can always hide it behind an extension method. And what to do best when there is no match heavily depends on the context.
I will make my contribution here... why? just because :p Its a different implementation, based on the Any LINQ extension, and a delegate. Here it is:
public static class Extensions
{
public static int IndexOf<T>(
this IEnumerable<T> list,
Predicate<T> condition) {
int i = -1;
return list.Any(x => { i++; return condition(x); }) ? i : -1;
}
}
void Main()
{
TestGetsFirstItem();
TestGetsLastItem();
TestGetsMinusOneOnNotFound();
TestGetsMiddleItem();
TestGetsMinusOneOnEmptyList();
}
void TestGetsFirstItem()
{
// Arrange
var list = new string[] { "a", "b", "c", "d" };
// Act
int index = list.IndexOf(item => item.Equals("a"));
// Assert
if(index != 0)
{
throw new Exception("Index should be 0 but is: " + index);
}
"Test Successful".Dump();
}
void TestGetsLastItem()
{
// Arrange
var list = new string[] { "a", "b", "c", "d" };
// Act
int index = list.IndexOf(item => item.Equals("d"));
// Assert
if(index != 3)
{
throw new Exception("Index should be 3 but is: " + index);
}
"Test Successful".Dump();
}
void TestGetsMinusOneOnNotFound()
{
// Arrange
var list = new string[] { "a", "b", "c", "d" };
// Act
int index = list.IndexOf(item => item.Equals("e"));
// Assert
if(index != -1)
{
throw new Exception("Index should be -1 but is: " + index);
}
"Test Successful".Dump();
}
void TestGetsMinusOneOnEmptyList()
{
// Arrange
var list = new string[] { };
// Act
int index = list.IndexOf(item => item.Equals("e"));
// Assert
if(index != -1)
{
throw new Exception("Index should be -1 but is: " + index);
}
"Test Successful".Dump();
}
void TestGetsMiddleItem()
{
// Arrange
var list = new string[] { "a", "b", "c", "d", "e" };
// Act
int index = list.IndexOf(item => item.Equals("c"));
// Assert
if(index != 2)
{
throw new Exception("Index should be 2 but is: " + index);
}
"Test Successful".Dump();
}
Here is a little extension I just put together.
public static class PositionsExtension
{
public static Int32 Position<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
return Positions<TSource>(source, predicate).FirstOrDefault();
}
public static IEnumerable<Int32> Positions<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
if (typeof(TSource) is IDictionary)
{
throw new Exception("Dictionaries aren't supported");
}
if (source == null)
{
throw new ArgumentOutOfRangeException("source is null");
}
if (predicate == null)
{
throw new ArgumentOutOfRangeException("predicate is null");
}
var found = source.Where(predicate).First();
var query = source.Select((item, index) => new
{
Found = ReferenceEquals(item, found),
Index = index
}).Where( it => it.Found).Select( it => it.Index);
return query;
}
}
Then you can call it like this.
IEnumerable<Int32> indicesWhereConditionIsMet =
ListItems.Positions(item => item == this);
Int32 firstWelcomeMessage ListItems.Position(msg =>
msg.WelcomeMessage.Contains("Hello"));
Here's an implementation of the highest-voted answer that returns -1 when the item is not found:
public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate)
{
var itemsWithIndices = items.Select((item, index) => new { Item = item, Index = index });
var matchingIndices =
from itemWithIndex in itemsWithIndices
where predicate(itemWithIndex.Item)
select (int?)itemWithIndex.Index;
return matchingIndices.FirstOrDefault() ?? -1;
}

How to check if contents of a List<String> is alphabetical [duplicate]

I am doing some unit tests and I want to know if there's any way to test if a list is ordered by a property of the objects it contains.
Right now I am doing it this way but I don't like it, I want a better way. Can somebody help me please?
// (fill the list)
List<StudyFeedItem> studyFeeds =
Feeds.GetStudyFeeds(2120, DateTime.Today.AddDays(-200), 20);
StudyFeedItem previous = studyFeeds.First();
foreach (StudyFeedItem item in studyFeeds)
{
if (item != previous)
{
Assert.IsTrue(previous.Date > item.Date);
}
previous = item;
}
If you are using MSTest, you may want to take a look at CollectionAssert.AreEqual.
Enumerable.SequenceEqual may be another useful API to use in an assertion.
In both cases you should prepare a list that holds the expected list in the expected order, and then compare that list to the result.
Here's an example:
var studyFeeds = Feeds.GetStudyFeeds(2120, DateTime.Today.AddDays(-200), 20);
var expectedList = studyFeeds.OrderByDescending(x => x.Date);
Assert.IsTrue(expectedList.SequenceEqual(studyFeeds));
A .NET 4.0 way would be to use the Enumerable.Zip method to zip the list with itself offset by one, which pairs each item with the subsequent item in the list. You can then check that the condition holds true for each pair, e.g.
var ordered = studyFeeds.Zip(studyFeeds.Skip(1), (a, b) => new { a, b })
.All(p => p.a.Date < p.b.Date);
If you're on an earlier version of the framework you can write your own Zip method without too much trouble, something like the following (argument validation and disposal of the enumerators if applicable is left to the reader):
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> selector)
{
var e1 = first.GetEnumerator();
var e2 = second.GetEnumerator();
while (e1.MoveNext() & e2.MoveNext()) // one & is important
yield return selector(e1.Current, e2.Current);
}
Nunit 2.5 introduced CollectionOrderedContraint and a nice syntax for verifying the order of a collection:
Assert.That(collection, Is.Ordered.By("PropertyName"));
No need to manually order and compare.
If your unit testing framework has helper methods to assert equality of collections, you should be able do something like this (NUnit flavored):
var sorted = studyFeeds.OrderBy(s => s.Date);
CollectionAssert.AreEqual(sorted.ToList(), studyFeeds.ToList());
The assert method works with any IEnumerable, but when both collections are of type IList or "array of something", the error message thrown when the assert fails will contain the index of the first out-of-place element.
The solutions posted involving sorting the list are expensive - determining if a list IS sorted can be done in O(N). Here's an extension method which will check:
public static bool IsOrdered<T>(this IList<T> list, IComparer<T> comparer = null)
{
if (comparer == null)
{
comparer = Comparer<T>.Default;
}
if (list.Count > 1)
{
for (int i = 1; i < list.Count; i++)
{
if (comparer.Compare(list[i - 1], list[i]) > 0)
{
return false;
}
}
}
return true;
}
A corresponding IsOrderedDescending could be implemented easily by changing > 0 to < 0.
Greg Beech answer, although excellent, can be simplified further by performing the test in the Zip itself. So instead of:
var ordered = studyFeeds.Zip(studyFeeds.Skip(1), (a, b) => new { a, b })
.All(p => p.a.Date <= p.b.Date);
You can simply do:
var ordered = !studyFeeds.Zip(studyFeeds.Skip(1), (a, b) => a.Date <= b.Date)
.Contains(false);
Which saves you one lambda expression and one anonymous type.
(In my opinion removing the anonymous type also makes it easier to read.)
if(studyFeeds.Length < 2)
return;
for(int i = 1; i < studyFeeds.Length;i++)
Assert.IsTrue(studyFeeds[i-1].Date > studyFeeds[i].Date);
for isn't dead just quite yet!
How about:
var list = items.ToList();
for(int i = 1; i < list.Count; i++) {
Assert.IsTrue(yourComparer.Compare(list[i - 1], list[i]) <= 0);
}
where yourComparer is an instance of YourComparer which implements IComparer<YourBusinessObject>. This ensures that every element is less than the next element in the enumeration.
Linq based answer is:
You can use SequenceEqual method to check if the original and ordered one is same or not.
var isOrderedAscending = lJobsList.SequenceEqual(lJobsList.OrderBy(x => x));
var isOrderedDescending = lJobsList.SequenceEqual(lJobsList.OrderByDescending(x => x));
Don't forget to import System.Linq namespace.
Additionally:
I am repeating that this answer is Linq based, you can achieve more efficiency by creating your custom extension method.
Also, if somebody still wants to use Linq and check if the sequence both is ordered in ascending or descending order, then you can achieve a little bit more efficiency like that:
var orderedSequence = lJobsList.OrderBy(x => x)
.ToList();
var reversedOrderSequence = orderedSequence.AsEnumerable()
.Reverse();
if (lJobsList.SequenceEqual(orderedSequence))
{
// Ordered in ascending
}
else (lJobsList.SequenceEqual(reversedOrderSequence))
{
// Ordered in descending
}
You could use an extension method like this:
public static System.ComponentModel.ListSortDirection? SortDirection<T>(this IEnumerable<T> items, Comparer<T> comparer = null)
{
if (items == null) throw new ArgumentNullException("items");
if (comparer == null) comparer = Comparer<T>.Default;
bool ascendingOrder = true; bool descendingOrder = true;
using (var e = items.GetEnumerator())
{
if (e.MoveNext())
{
T last = e.Current; // first item
while (e.MoveNext())
{
int diff = comparer.Compare(last, e.Current);
if (diff > 0)
ascendingOrder = false;
else if (diff < 0)
descendingOrder = false;
if (!ascendingOrder && !descendingOrder)
break;
last = e.Current;
}
}
}
if (ascendingOrder)
return System.ComponentModel.ListSortDirection.Ascending;
else if (descendingOrder)
return System.ComponentModel.ListSortDirection.Descending;
else
return null;
}
It enables to check if the sequence is sorted and also determines the direction:
var items = new[] { 3, 2, 1, 1, 0 };
var sort = items.SortDirection();
Console.WriteLine("Is sorted? {0}, Direction: {1}", sort.HasValue, sort);
//Is sorted? True, Direction: Descending
Here's how I do it with Linq and I comparable, might not be the best but works for me and it's test framework independent.
So the call looks like this:
myList.IsOrderedBy(a => a.StartDate)
This works for anything that implements IComparable, so numbers strings and anything that inherit from IComparable:
public static bool IsOrderedBy<T, TProperty>(this List<T> list, Expression<Func<T, TProperty>> propertyExpression) where TProperty : IComparable<TProperty>
{
var member = (MemberExpression) propertyExpression.Body;
var propertyInfo = (PropertyInfo) member.Member;
IComparable<TProperty> previousValue = null;
for (int i = 0; i < list.Count(); i++)
{
var currentValue = (TProperty)propertyInfo.GetValue(list[i], null);
if (previousValue == null)
{
previousValue = currentValue;
continue;
}
if(previousValue.CompareTo(currentValue) > 0) return false;
previousValue = currentValue;
}
return true;
}
Hope this helps, took me ages to work this one out.
Checking a sequence can have four different outcomes. Same means that all elements in the sequence are the same (or the sequence is empty):
enum Sort {
Unsorted,
Same,
SortedAscending,
SortedDescending
}
Here is a way to check the sorting of a sequence:
Sort GetSort<T>(IEnumerable<T> source, IComparer<T> comparer = null) {
if (source == null)
throw new ArgumentNullException(nameof(source));
if (comparer == null)
comparer = Comparer<T>.Default;
using (var enumerator = source.GetEnumerator()) {
if (!enumerator.MoveNext())
return Sort.Same;
Sort? result = null;
var previousItem = enumerator.Current;
while (enumerator.MoveNext()) {
var nextItem = enumerator.Current;
var comparison = comparer.Compare(previousItem, nextItem);
if (comparison < 0) {
if (result == Sort.SortedDescending)
return Sort.Unsorted;
result = Sort.SortedAscending;
}
else if (comparison > 0) {
if (result == Sort.SortedAscending)
return Sort.Unsorted;
result = Sort.SortedDescending;
}
}
return result ?? Sort.Same;
}
}
I'm using the enumerator directly instead of a foreach loop because I need to examine the elements of the sequence as pairs. It makes the code more complex but is also more efficient.
Something LINQ-y would be to use a separate sorted query...
var sorted = from item in items
orderby item.Priority
select item;
Assert.IsTrue(items.SequenceEquals(sorted));
Type inference means you'd need a
where T : IHasPriority
However, if you have multiple items of the same priority, then for a unit test assertion you're probably best off just looping with the list index as Jason suggested.
One way or another you're going to have to walk the list and ensure that the items are in the order you want. Since the item comparison is custom, you could look into creating a generic method for this and passing in a comparison function - the same way that sorting the list uses comparison functions.
You can create an ordered and an unordered version of the list first:
var asc = jobs.OrderBy(x => x);
var desc = jobs.OrderByDescending(x => x);
Now compare the original list with both:
if (jobs.SequenceEqual(asc) || jobs.SequenceEquals(desc)) // ...
var studyFeeds = Feeds.GetStudyFeeds(2120, DateTime.Today.AddDays(-200), 20);
var orderedFeeds = studyFeeds.OrderBy(f => f.Date);
for (int i = 0; i < studyFeeds.Count; i++)
{
Assert.AreEqual(orderedFeeds[i].Date, studyFeeds[i].Date);
}
What about something like this, without sorting the list
public static bool IsAscendingOrder<T>(this IEnumerable<T> seq) where T : IComparable
{
var seqArray = seq as T[] ?? seq.ToArray();
return !seqArray.Where((e, i) =>
i < seqArray.Count() - 1 &&
e.CompareTo(seqArray.ElementAt(i + 1)) >= 0).Any();
}
Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert.AreEqual(
mylist.OrderBy((a) => a.SomeProperty).ToList(),
mylist,
"Not sorted.");
Here's a more lightweight generic version. To test for descending order, change the >= 0 comparison to <= 0.
public static bool IsAscendingOrder<T>(this IEnumerable<T> seq) where T : IComparable<T>
{
var predecessor = default(T);
var hasPredecessor = false;
foreach(var x in seq)
{
if (hasPredecessor && predecessor.CompareTo(x) >= 0) return false;
predecessor = x;
hasPredecessor = true;
}
return true;
}
Tests:
new int[] { }.IsAscendingOrder() returns true
new int[] { 1 }.IsAscendingOrder() returns true
new int[] { 1,2 }.IsAscendingOrder() returns true
new int[] { 1,2,0 }.IsAscendingOrder() returns false
While AnorZaken's and Greg Beech's answers are very nice, as they don't require using an extension method, it can be good to avoid Zip() sometimes, as some enumerables can be expensive to enumerate in this way.
A solution can be found in Aggregate()
double[] score1 = new double[] { 12.2, 13.3, 5, 17.2, 2.2, 4.5 };
double[] score2 = new double[] { 2.2, 4.5, 5, 12.2, 13.3, 17.2 };
bool isordered1 = score1.Aggregate(double.MinValue,(accum,elem)=>elem>=accum?elem:double.MaxValue) < double.MaxValue;
bool isordered2 = score2.Aggregate(double.MinValue,(accum,elem)=>elem>=accum?elem:double.MaxValue) < double.MaxValue;
Console.WriteLine ("isordered1 {0}",isordered1);
Console.WriteLine ("isordered2 {0}",isordered2);
One thing a little ugly about the above solution, is the double less-than comparisons. Floating comparisons like this make me queasy as it is almost like a floating point equality comparison. But it seems to work for double here. Integer values would be fine, also.
The floating point comparison can be avoided by using nullable types, but then the code becomes a bit harder to read.
double[] score3 = new double[] { 12.2, 13.3, 5, 17.2, 2.2, 4.5 };
double[] score4 = new double[] { 2.2, 4.5, 5, 12.2, 13.3, 17.2 };
bool isordered3 = score3.Aggregate((double?)double.MinValue,(accum,elem)=>(elem>(accum??(double?)double.MaxValue).Value)?(double?)elem:(double?)null) !=null;
bool isordered4 = score4.Aggregate((double?)double.MinValue,(accum,elem)=>(elem>(accum??(double?)double.MaxValue).Value)?(double?)elem:(double?)null) !=null;
Console.WriteLine ("isordered3 {0}",isordered3);
Console.WriteLine ("isordered4 {0}",isordered4);
You can use lambda in extension:
public static bool IsAscending<T>(this IEnumerable<T> self, Func<T, T, int> compareTo) {
var list = self as IList<T> ?? self.ToList();
if (list.Count < 2) {
return true;
}
T a = list[0];
for (int i = 1; i < list.Count; i++) {
T b = list[i];
if (compareTo(a, b) > 0) {
return false;
}
a = b;
}
return true;
}
Using:
bool result1 = Enumerable.Range(2, 10).IsAscending((a, b) => a.CompareTo(b));
more:
var lst = new List<(int, string)> { (1, "b"), (2, "a"), (3, "s1"), (3, "s") };
bool result2 = lst.IsAscending((a, b) => {
var cmp = a.Item1.CompareTo(b.Item1);
if (cmp != 0) {
return cmp;
} else {
return a.Item2.CompareTo(b.Item2);
}
});
var expectedList = resultA.ToArray();
var actualList = resultB.ToArray();
var i = 0;
foreach (var item in expectedList)
{
Assert.True(expectedList[i].id == actualList[i].id);
i++;
}

Aggregate values until a limit is reached

I need something similar to an AggregateWhile method. The standard System.Linq.Enumerable class doesn't provide it. Until now I've always been able to leverage the standard LINQ methods to solve every problem I've encountered. So I'd like to know if that's still possible in this case, or if I really do need to extend LINQ with a non-standard method.
The hypothetical AggregateWhile method would iterate over a sequence and apply the accumulator. The aggregation would be complete once a predicate returns false. The result is the aggregration of elements up to but not including the element for which the predicate failed.
Here's an example. We have a List { 1, 2, 3, 4, 5 } with an accumulator that adds the two input numbers together, and a predicate that states the accumulation must be less than 12. AggregateWhile would return 10 since that's the result of 1 + 2 + 3 + 4 and adding the final 5 would push the total over the limit. In code:
var list = new List<int> { 1, 2, 3, 4, 5 };
int total = list.AggregateWhile( (x, y) => x + y, a => a < 12 ); // returns 10
I need a purely functional solution, so closing over a temporary variable is not an option.
You could either write the function yourself, or carry a flag with your accumulator:
int total = list.Aggregate(new { value = 0, valid = true },
(acc, v) => acc.value + v < 12 && acc.valid ?
new { value = acc.value + v, valid = true } :
new { value = acc.value, valid = false },
acc => acc.value);
It's quite ugly, so writting a new AggregateWhile would be nicer:
public static TSource AggregateWhile<TSource>(this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func,
Func<TSource, bool> predicate)
{
using (IEnumerator<TSource> e = source.GetEnumerator()) {
TSource result = e.Current;
TSource tmp = default(TSource);
while (e.MoveNext() && predicate(tmp = func(result, e.Current)))
result = tmp;
return result;
}
}
(no error checking for brevity)
You can write your own extension method. This is not as perfect as the normal Linq methods, I cheated because I already know your requirements to make it simpler. In reality you may want an optional starting value for a and maybe different In and output types for T or other stuff:
public static class Linq
{
public static T AggregateWhile<T>(this IEnumerable<T> sequence, Func<T, T, T> aggregate, Func<T, bool> predicate)
{
T a;
foreach(var value in sequence)
{
T temp = aggregate(a, value);
if(!predicate(temp)) break;
a = temp;
}
return a;
}
}
Won't this work?
int total = list.Aggregate(0, (a, x) => (a + x) > 12 ? a : a + x);
Using Tuple<bool, int> as accumulator type, to break on first overflow:
int total = list.Aggregate(new Tuple<bool, int>(false, 0),
(a, x) => a.Item1 || (a.Item2 + x) > 12
? new Tuple<bool, int>(true, a.Item2)
: new Tuple<bool, int>(false, a.Item2 + x)
).Item2;
But it isn't so nice unfortunately.
Start using F#. ;)
let list = [ 1; 2; 3; 4; 5; 1 ]
let predicate = fun a -> a > 12
let total = list |> List.fold (fun (aval, astate) x ->
if astate || predicate (aval + x)
then (aval, true)
else (aval + x, false)) (0, false)
Tuple unpacking, no new bloat. And when you code it type inference makes it a breeze.
I asked this question a while back while encountering a problem that I later reframed into not needing AggregateWhile. But now I've encountered a slightly different problem which undoubtedly requires AggregateWhile or some direct substitute for it.
The solutions proposed by #sloth and #rkrahl are helpful. But they fall short in that the aggregation logic (addition in this case) is repeated twice. This doesn't seem like a big deal for the question's trivial example. But for my real problem, the calculation is complex so writing it twice is unacceptable.
Here's the solution I prefer (short of actual AggregateWhile methods):
class Program
{
static void Main( string[] args ) { new Program(); }
public Program()
{
var list = new int[] { 1, 2, 3, 4, 5 };
int total = list
.Aggregate( new Accumulator( 0 ), ( a, i ) => a.Next( i ), a => a.Total );
}
}
class Accumulator
{
public Accumulator( int total )
{
this.total = total;
}
public Accumulator Next( int i )
{
if ( isDone )
return this;
else {
int total = this.total + i;
if ( total < 12 )
return new Accumulator( total );
else {
isDone = true;
return this;
}
}
}
bool isDone;
public int Total
{
get { return total; }
}
readonly int total;
}
The ideal solution are fully implemented and tested AggregateWhile methods which correspond to the three Aggregate overloads. Short of that, the above pattern has the advantage that it can leverage the (somewhat lacking) functionality that's already present in the .NET framework.
Here is an AggregateWhile with a seed:
public static TAccumulate AggregateWhile<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, bool> predicate)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (func == null)
throw new ArgumentNullException(nameof(func));
if (predicate == null)
throw new ArgumentNullException(nameof(predicate));
var accumulate = seed;
foreach (var item in source)
{
var tmp = func(accumulate, item);
if (!predicate(tmp)) break;
accumulate = tmp;
}
return accumulate;
}

Get previous and next item in a IEnumerable using LINQ

I have an IEnumerable of a custom type. (That I've gotten from a SelectMany)
I also have an item (myItem) in that IEnumerable that I desire the previous and next item from the IEnumerable.
Currently, I'm doing the desired like this:
var previousItem = myIEnumerable.Reverse().SkipWhile(
i => i.UniqueObjectID != myItem.UniqueObjectID).Skip(1).FirstOrDefault();
I can get the next item by simply ommitting the .Reverse.
or, I could:
int index = myIEnumerable.ToList().FindIndex(
i => i.UniqueObjectID == myItem.UniqueObjectID)
and then use .ElementAt(index +/- 1) to get the previous or next item.
Which is better between the two options?
Is there an even better option available?
"Better" includes a combination of performance (memory and speed) and readability; with readability being my primary concern.
First off
"Better" includes a combination of performance (memory and speed)
In general you can't have both, the rule of thumb is, if you optimise for speed, it'll cost memory, if you optimise for memory, it'll cost you speed.
There is a better option, that performs well on both memory and speed fronts, and can be used in a readable manner (I'm not delighted with the function name, however, FindItemReturningPreviousItemFoundItemAndNextItem is a bit of a mouthful).
So, it looks like it's time for a custom find extension method, something like . . .
public static IEnumerable<T> FindSandwichedItem<T>(this IEnumerable<T> items, Predicate<T> matchFilling)
{
if (items == null)
throw new ArgumentNullException("items");
if (matchFilling == null)
throw new ArgumentNullException("matchFilling");
return FindSandwichedItemImpl(items, matchFilling);
}
private static IEnumerable<T> FindSandwichedItemImpl<T>(IEnumerable<T> items, Predicate<T> matchFilling)
{
using(var iter = items.GetEnumerator())
{
T previous = default(T);
while(iter.MoveNext())
{
if(matchFilling(iter.Current))
{
yield return previous;
yield return iter.Current;
if (iter.MoveNext())
yield return iter.Current;
else
yield return default(T);
yield break;
}
previous = iter.Current;
}
}
// If we get here nothing has been found so return three default values
yield return default(T); // Previous
yield return default(T); // Current
yield return default(T); // Next
}
You can cache the result of this to a list if you need to refer to the items more than once, but it returns the found item, preceded by the previous item, followed by the following item. e.g.
var sandwichedItems = myIEnumerable.FindSandwichedItem(item => item.objectId == "MyObjectId").ToList();
var previousItem = sandwichedItems[0];
var myItem = sandwichedItems[1];
var nextItem = sandwichedItems[2];
The defaults to return if it's the first or last item may need to change depending on your requirements.
Hope this helps.
For readability, I'd load the IEnumerable into a linked list:
var e = Enumerable.Range(0,100);
var itemIKnow = 50;
var linkedList = new LinkedList<int>(e);
var listNode = linkedList.Find(itemIKnow);
var next = listNode.Next.Value; //probably a good idea to check for null
var prev = listNode.Previous.Value; //ditto
By creating an extension method for establishing context to the current element you can use a Linq query like this:
var result = myIEnumerable.WithContext()
.Single(i => i.Current.UniqueObjectID == myItem.UniqueObjectID);
var previous = result.Previous;
var next = result.Next;
The extension would be something like this:
public class ElementWithContext<T>
{
public T Previous { get; private set; }
public T Next { get; private set; }
public T Current { get; private set; }
public ElementWithContext(T current, T previous, T next)
{
Current = current;
Previous = previous;
Next = next;
}
}
public static class LinqExtensions
{
public static IEnumerable<ElementWithContext<T>>
WithContext<T>(this IEnumerable<T> source)
{
T previous = default(T);
T current = source.FirstOrDefault();
foreach (T next in source.Union(new[] { default(T) }).Skip(1))
{
yield return new ElementWithContext<T>(current, previous, next);
previous = current;
current = next;
}
}
}
You could cache the enumerable in a list
var myList = myIEnumerable.ToList()
iterate over it by index
for (int i = 0; i < myList.Count; i++)
then the current element is myList[i], the previous element is myList[i-1], and the next element is myList[i+1]
(Don't forget about the special cases of the first and last elements in the list.)
You are really over complicating things:
Sometimes just a for loop is going to be better to do something, and I think provide a clearer implementation of what you are trying to do/
var myList = myIEnumerable.ToList();
for(i = 0; i < myList.Length; i++)
{
if(myList[i].UniqueObjectID == myItem.UniqueObjectID)
{
previousItem = myList[(i - 1) % (myList.Length - 1)];
nextItem = myList[(i + 1) % (myList.Length - 1)];
}
}
Here is a LINQ extension method that returns the current item, along with the previous and the next. It yields ValueTuple<T, T, T> values to avoid allocations. The source is enumerated once.
/// <summary>
/// Projects each element of a sequence into a tuple that includes the previous
/// and the next element.
/// </summary>
public static IEnumerable<(T Previous, T Current, T Next)> WithPreviousAndNext<T>(
this IEnumerable<T> source, T firstPrevious = default, T lastNext = default)
{
ArgumentNullException.ThrowIfNull(source);
(T Previous, T Current, bool HasPrevious) queue = (default, firstPrevious, false);
foreach (var item in source)
{
if (queue.HasPrevious)
yield return (queue.Previous, queue.Current, item);
queue = (queue.Current, item, true);
}
if (queue.HasPrevious)
yield return (queue.Previous, queue.Current, lastNext);
}
Usage example:
var source = Enumerable.Range(1, 5);
Console.WriteLine($"Source: {String.Join(", ", source)}");
var result = source.WithPreviousAndNext(firstPrevious: -1, lastNext: -1);
Console.WriteLine($"Result: {String.Join(", ", result)}");
Output:
Source: 1, 2, 3, 4, 5
Result: (-1, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, -1)
To get the previous and the next of a specific item, you could use tuple deconstruction:
var (previous, current, next) = myIEnumerable
.WithPreviousAndNext()
.First(e => e.Current.UniqueObjectID == myItem.UniqueObjectID);
CPU
Depends entirely on where the object is in the sequence. If it is located at the end I would expect the second to be faster with more than a factor 2 (but only a constant factor). If it is located in the beginning the first will be faster because you don't traverse the whole list.
Memory
The first is iterating the sequence without saving the sequence so the memory hit will be very small. The second solution will take as much memory as the length of the list * references + objects + overhead.
I thought I would try to answer this using Zip from Linq.
string[] items = {"nought","one","two","three","four"};
var item = items[2];
var sandwiched =
items
.Zip( items.Skip(1), (previous,current) => new { previous, current } )
.Zip( items.Skip(2), (pair,next) => new { pair.previous, pair.current, next } )
.FirstOrDefault( triplet => triplet.current == item );
This will return a anonymous type {previous,current,next}.
Unfortunately this will only work for indexes 1,2 and 3.
string[] items = {"nought","one","two","three","four"};
var item = items[4];
var pad1 = Enumerable.Repeat( "", 1 );
var pad2 = Enumerable.Repeat( "", 2 );
var padded = pad1.Concat( items );
var next1 = items.Concat( pad1 );
var next2 = items.Skip(1).Concat( pad2 );
var sandwiched =
padded
.Zip( next1, (previous,current) => new { previous, current } )
.Zip( next2, (pair,next) => new { pair.previous, pair.current, next } )
.FirstOrDefault( triplet => triplet.current == item );
This version will work for all indexes.
Both version use lazy evaluation courtesy of Linq.
Here are some extension methods as promised. The names are generic and reusable with any type simple and there are lookup overloads to get at the item needed to get the next or previous items. I would benchmark the solutions and then see where you could squeeze cycles out.
public static class ExtensionMethods
{
public static T Previous<T>(this List<T> list, T item) {
var index = list.IndexOf(item) - 1;
return index > -1 ? list[index] : default(T);
}
public static T Next<T>(this List<T> list, T item) {
var index = list.IndexOf(item) + 1;
return index < list.Count() ? list[index] : default(T);
}
public static T Previous<T>(this List<T> list, Func<T, Boolean> lookup) {
var item = list.SingleOrDefault(lookup);
var index = list.IndexOf(item) - 1;
return index > -1 ? list[index] : default(T);
}
public static T Next<T>(this List<T> list, Func<T,Boolean> lookup) {
var item = list.SingleOrDefault(lookup);
var index = list.IndexOf(item) + 1;
return index < list.Count() ? list[index] : default(T);
}
public static T PreviousOrFirst<T>(this List<T> list, T item) {
if(list.Count() < 1)
throw new Exception("No array items!");
var previous = list.Previous(item);
return previous == null ? list.First() : previous;
}
public static T NextOrLast<T>(this List<T> list, T item) {
if(list.Count() < 1)
throw new Exception("No array items!");
var next = list.Next(item);
return next == null ? list.Last() : next;
}
public static T PreviousOrFirst<T>(this List<T> list, Func<T,Boolean> lookup) {
if(list.Count() < 1)
throw new Exception("No array items!");
var previous = list.Previous(lookup);
return previous == null ? list.First() : previous;
}
public static T NextOrLast<T>(this List<T> list, Func<T,Boolean> lookup) {
if(list.Count() < 1)
throw new Exception("No array items!");
var next = list.Next(lookup);
return next == null ? list.Last() : next;
}
}
And you can use them like this.
var previous = list.Previous(obj);
var next = list.Next(obj);
var previousWithLookup = list.Previous((o) => o.LookupProperty == otherObj.LookupProperty);
var nextWithLookup = list.Next((o) => o.LookupProperty == otherObj.LookupProperty);
var previousOrFirst = list.PreviousOrFirst(obj);
var nextOrLast = list.NextOrLast(ob);
var previousOrFirstWithLookup = list.PreviousOrFirst((o) => o.LookupProperty == otherObj.LookupProperty);
var nextOrLastWithLookup = list.NextOrLast((o) => o.LookupProperty == otherObj.LookupProperty);
I use the following technique:
var items = new[] { "Bob", "Jon", "Zac" };
var sandwiches = items
.Sandwich()
.ToList();
Which produces this result:
Notice that there are nulls for the first Previous value, and the last Next value.
It uses the following extension method:
public static IEnumerable<(T Previous, T Current, T Next)> Sandwich<T>(this IEnumerable<T> source, T beforeFirst = default, T afterLast = default)
{
var sourceList = source.ToList();
T previous = beforeFirst;
T current = sourceList.FirstOrDefault();
foreach (var next in sourceList.Skip(1))
{
yield return (previous, current, next);
previous = current;
current = next;
}
yield return (previous, current, afterLast);
}
If you need it for every element in myIEnumerable I’d just iterate through it keeping references to the 2 previous elements. In the body of the loop I'd do the processing for the second previous element and the current would be its descendant and first previous its ancestor.
If you need it for only one element I'd choose your first approach.

Simple sort verification for unit testing an ORDER BY? [duplicate]

I am doing some unit tests and I want to know if there's any way to test if a list is ordered by a property of the objects it contains.
Right now I am doing it this way but I don't like it, I want a better way. Can somebody help me please?
// (fill the list)
List<StudyFeedItem> studyFeeds =
Feeds.GetStudyFeeds(2120, DateTime.Today.AddDays(-200), 20);
StudyFeedItem previous = studyFeeds.First();
foreach (StudyFeedItem item in studyFeeds)
{
if (item != previous)
{
Assert.IsTrue(previous.Date > item.Date);
}
previous = item;
}
If you are using MSTest, you may want to take a look at CollectionAssert.AreEqual.
Enumerable.SequenceEqual may be another useful API to use in an assertion.
In both cases you should prepare a list that holds the expected list in the expected order, and then compare that list to the result.
Here's an example:
var studyFeeds = Feeds.GetStudyFeeds(2120, DateTime.Today.AddDays(-200), 20);
var expectedList = studyFeeds.OrderByDescending(x => x.Date);
Assert.IsTrue(expectedList.SequenceEqual(studyFeeds));
A .NET 4.0 way would be to use the Enumerable.Zip method to zip the list with itself offset by one, which pairs each item with the subsequent item in the list. You can then check that the condition holds true for each pair, e.g.
var ordered = studyFeeds.Zip(studyFeeds.Skip(1), (a, b) => new { a, b })
.All(p => p.a.Date < p.b.Date);
If you're on an earlier version of the framework you can write your own Zip method without too much trouble, something like the following (argument validation and disposal of the enumerators if applicable is left to the reader):
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> selector)
{
var e1 = first.GetEnumerator();
var e2 = second.GetEnumerator();
while (e1.MoveNext() & e2.MoveNext()) // one & is important
yield return selector(e1.Current, e2.Current);
}
Nunit 2.5 introduced CollectionOrderedContraint and a nice syntax for verifying the order of a collection:
Assert.That(collection, Is.Ordered.By("PropertyName"));
No need to manually order and compare.
If your unit testing framework has helper methods to assert equality of collections, you should be able do something like this (NUnit flavored):
var sorted = studyFeeds.OrderBy(s => s.Date);
CollectionAssert.AreEqual(sorted.ToList(), studyFeeds.ToList());
The assert method works with any IEnumerable, but when both collections are of type IList or "array of something", the error message thrown when the assert fails will contain the index of the first out-of-place element.
The solutions posted involving sorting the list are expensive - determining if a list IS sorted can be done in O(N). Here's an extension method which will check:
public static bool IsOrdered<T>(this IList<T> list, IComparer<T> comparer = null)
{
if (comparer == null)
{
comparer = Comparer<T>.Default;
}
if (list.Count > 1)
{
for (int i = 1; i < list.Count; i++)
{
if (comparer.Compare(list[i - 1], list[i]) > 0)
{
return false;
}
}
}
return true;
}
A corresponding IsOrderedDescending could be implemented easily by changing > 0 to < 0.
Greg Beech answer, although excellent, can be simplified further by performing the test in the Zip itself. So instead of:
var ordered = studyFeeds.Zip(studyFeeds.Skip(1), (a, b) => new { a, b })
.All(p => p.a.Date <= p.b.Date);
You can simply do:
var ordered = !studyFeeds.Zip(studyFeeds.Skip(1), (a, b) => a.Date <= b.Date)
.Contains(false);
Which saves you one lambda expression and one anonymous type.
(In my opinion removing the anonymous type also makes it easier to read.)
if(studyFeeds.Length < 2)
return;
for(int i = 1; i < studyFeeds.Length;i++)
Assert.IsTrue(studyFeeds[i-1].Date > studyFeeds[i].Date);
for isn't dead just quite yet!
How about:
var list = items.ToList();
for(int i = 1; i < list.Count; i++) {
Assert.IsTrue(yourComparer.Compare(list[i - 1], list[i]) <= 0);
}
where yourComparer is an instance of YourComparer which implements IComparer<YourBusinessObject>. This ensures that every element is less than the next element in the enumeration.
Linq based answer is:
You can use SequenceEqual method to check if the original and ordered one is same or not.
var isOrderedAscending = lJobsList.SequenceEqual(lJobsList.OrderBy(x => x));
var isOrderedDescending = lJobsList.SequenceEqual(lJobsList.OrderByDescending(x => x));
Don't forget to import System.Linq namespace.
Additionally:
I am repeating that this answer is Linq based, you can achieve more efficiency by creating your custom extension method.
Also, if somebody still wants to use Linq and check if the sequence both is ordered in ascending or descending order, then you can achieve a little bit more efficiency like that:
var orderedSequence = lJobsList.OrderBy(x => x)
.ToList();
var reversedOrderSequence = orderedSequence.AsEnumerable()
.Reverse();
if (lJobsList.SequenceEqual(orderedSequence))
{
// Ordered in ascending
}
else (lJobsList.SequenceEqual(reversedOrderSequence))
{
// Ordered in descending
}
You could use an extension method like this:
public static System.ComponentModel.ListSortDirection? SortDirection<T>(this IEnumerable<T> items, Comparer<T> comparer = null)
{
if (items == null) throw new ArgumentNullException("items");
if (comparer == null) comparer = Comparer<T>.Default;
bool ascendingOrder = true; bool descendingOrder = true;
using (var e = items.GetEnumerator())
{
if (e.MoveNext())
{
T last = e.Current; // first item
while (e.MoveNext())
{
int diff = comparer.Compare(last, e.Current);
if (diff > 0)
ascendingOrder = false;
else if (diff < 0)
descendingOrder = false;
if (!ascendingOrder && !descendingOrder)
break;
last = e.Current;
}
}
}
if (ascendingOrder)
return System.ComponentModel.ListSortDirection.Ascending;
else if (descendingOrder)
return System.ComponentModel.ListSortDirection.Descending;
else
return null;
}
It enables to check if the sequence is sorted and also determines the direction:
var items = new[] { 3, 2, 1, 1, 0 };
var sort = items.SortDirection();
Console.WriteLine("Is sorted? {0}, Direction: {1}", sort.HasValue, sort);
//Is sorted? True, Direction: Descending
Here's how I do it with Linq and I comparable, might not be the best but works for me and it's test framework independent.
So the call looks like this:
myList.IsOrderedBy(a => a.StartDate)
This works for anything that implements IComparable, so numbers strings and anything that inherit from IComparable:
public static bool IsOrderedBy<T, TProperty>(this List<T> list, Expression<Func<T, TProperty>> propertyExpression) where TProperty : IComparable<TProperty>
{
var member = (MemberExpression) propertyExpression.Body;
var propertyInfo = (PropertyInfo) member.Member;
IComparable<TProperty> previousValue = null;
for (int i = 0; i < list.Count(); i++)
{
var currentValue = (TProperty)propertyInfo.GetValue(list[i], null);
if (previousValue == null)
{
previousValue = currentValue;
continue;
}
if(previousValue.CompareTo(currentValue) > 0) return false;
previousValue = currentValue;
}
return true;
}
Hope this helps, took me ages to work this one out.
Checking a sequence can have four different outcomes. Same means that all elements in the sequence are the same (or the sequence is empty):
enum Sort {
Unsorted,
Same,
SortedAscending,
SortedDescending
}
Here is a way to check the sorting of a sequence:
Sort GetSort<T>(IEnumerable<T> source, IComparer<T> comparer = null) {
if (source == null)
throw new ArgumentNullException(nameof(source));
if (comparer == null)
comparer = Comparer<T>.Default;
using (var enumerator = source.GetEnumerator()) {
if (!enumerator.MoveNext())
return Sort.Same;
Sort? result = null;
var previousItem = enumerator.Current;
while (enumerator.MoveNext()) {
var nextItem = enumerator.Current;
var comparison = comparer.Compare(previousItem, nextItem);
if (comparison < 0) {
if (result == Sort.SortedDescending)
return Sort.Unsorted;
result = Sort.SortedAscending;
}
else if (comparison > 0) {
if (result == Sort.SortedAscending)
return Sort.Unsorted;
result = Sort.SortedDescending;
}
}
return result ?? Sort.Same;
}
}
I'm using the enumerator directly instead of a foreach loop because I need to examine the elements of the sequence as pairs. It makes the code more complex but is also more efficient.
Something LINQ-y would be to use a separate sorted query...
var sorted = from item in items
orderby item.Priority
select item;
Assert.IsTrue(items.SequenceEquals(sorted));
Type inference means you'd need a
where T : IHasPriority
However, if you have multiple items of the same priority, then for a unit test assertion you're probably best off just looping with the list index as Jason suggested.
One way or another you're going to have to walk the list and ensure that the items are in the order you want. Since the item comparison is custom, you could look into creating a generic method for this and passing in a comparison function - the same way that sorting the list uses comparison functions.
You can create an ordered and an unordered version of the list first:
var asc = jobs.OrderBy(x => x);
var desc = jobs.OrderByDescending(x => x);
Now compare the original list with both:
if (jobs.SequenceEqual(asc) || jobs.SequenceEquals(desc)) // ...
var studyFeeds = Feeds.GetStudyFeeds(2120, DateTime.Today.AddDays(-200), 20);
var orderedFeeds = studyFeeds.OrderBy(f => f.Date);
for (int i = 0; i < studyFeeds.Count; i++)
{
Assert.AreEqual(orderedFeeds[i].Date, studyFeeds[i].Date);
}
What about something like this, without sorting the list
public static bool IsAscendingOrder<T>(this IEnumerable<T> seq) where T : IComparable
{
var seqArray = seq as T[] ?? seq.ToArray();
return !seqArray.Where((e, i) =>
i < seqArray.Count() - 1 &&
e.CompareTo(seqArray.ElementAt(i + 1)) >= 0).Any();
}
Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert.AreEqual(
mylist.OrderBy((a) => a.SomeProperty).ToList(),
mylist,
"Not sorted.");
Here's a more lightweight generic version. To test for descending order, change the >= 0 comparison to <= 0.
public static bool IsAscendingOrder<T>(this IEnumerable<T> seq) where T : IComparable<T>
{
var predecessor = default(T);
var hasPredecessor = false;
foreach(var x in seq)
{
if (hasPredecessor && predecessor.CompareTo(x) >= 0) return false;
predecessor = x;
hasPredecessor = true;
}
return true;
}
Tests:
new int[] { }.IsAscendingOrder() returns true
new int[] { 1 }.IsAscendingOrder() returns true
new int[] { 1,2 }.IsAscendingOrder() returns true
new int[] { 1,2,0 }.IsAscendingOrder() returns false
While AnorZaken's and Greg Beech's answers are very nice, as they don't require using an extension method, it can be good to avoid Zip() sometimes, as some enumerables can be expensive to enumerate in this way.
A solution can be found in Aggregate()
double[] score1 = new double[] { 12.2, 13.3, 5, 17.2, 2.2, 4.5 };
double[] score2 = new double[] { 2.2, 4.5, 5, 12.2, 13.3, 17.2 };
bool isordered1 = score1.Aggregate(double.MinValue,(accum,elem)=>elem>=accum?elem:double.MaxValue) < double.MaxValue;
bool isordered2 = score2.Aggregate(double.MinValue,(accum,elem)=>elem>=accum?elem:double.MaxValue) < double.MaxValue;
Console.WriteLine ("isordered1 {0}",isordered1);
Console.WriteLine ("isordered2 {0}",isordered2);
One thing a little ugly about the above solution, is the double less-than comparisons. Floating comparisons like this make me queasy as it is almost like a floating point equality comparison. But it seems to work for double here. Integer values would be fine, also.
The floating point comparison can be avoided by using nullable types, but then the code becomes a bit harder to read.
double[] score3 = new double[] { 12.2, 13.3, 5, 17.2, 2.2, 4.5 };
double[] score4 = new double[] { 2.2, 4.5, 5, 12.2, 13.3, 17.2 };
bool isordered3 = score3.Aggregate((double?)double.MinValue,(accum,elem)=>(elem>(accum??(double?)double.MaxValue).Value)?(double?)elem:(double?)null) !=null;
bool isordered4 = score4.Aggregate((double?)double.MinValue,(accum,elem)=>(elem>(accum??(double?)double.MaxValue).Value)?(double?)elem:(double?)null) !=null;
Console.WriteLine ("isordered3 {0}",isordered3);
Console.WriteLine ("isordered4 {0}",isordered4);
You can use lambda in extension:
public static bool IsAscending<T>(this IEnumerable<T> self, Func<T, T, int> compareTo) {
var list = self as IList<T> ?? self.ToList();
if (list.Count < 2) {
return true;
}
T a = list[0];
for (int i = 1; i < list.Count; i++) {
T b = list[i];
if (compareTo(a, b) > 0) {
return false;
}
a = b;
}
return true;
}
Using:
bool result1 = Enumerable.Range(2, 10).IsAscending((a, b) => a.CompareTo(b));
more:
var lst = new List<(int, string)> { (1, "b"), (2, "a"), (3, "s1"), (3, "s") };
bool result2 = lst.IsAscending((a, b) => {
var cmp = a.Item1.CompareTo(b.Item1);
if (cmp != 0) {
return cmp;
} else {
return a.Item2.CompareTo(b.Item2);
}
});
var expectedList = resultA.ToArray();
var actualList = resultB.ToArray();
var i = 0;
foreach (var item in expectedList)
{
Assert.True(expectedList[i].id == actualList[i].id);
i++;
}

Categories