How to iterate a collection between two items? - c#

Consider for example a List of objects:
List<MyClass> myList;
I have a method which passes two references to items within the list. I want to iterate all items within the given ones (note: I don't know which of the two items comes first within the list):
privat void MyFunction(MyClass listItem, MyClass anotherListItem)
{
foreach(var item in ????)
{
// do something
}
}
Currently I have solved this usecase as follows:
int listItemIdx = myList.IndexOf(listItem);
int anotherListItemIdx = myList.IndexOf(anotherListItem);
if(listItemIdx < anotherListItemIdx )
{
for(int i = listItemIdx ; i <= anotherListItemIdx ; i++)
{
// do stuff
}
}
else
{
for (int i = anotherListItemIdx ; i < listItemIdx ; i++)
{
// do stuff
}
}
I was wondering if there is a more elegant, efficient or built-in solution to this problem?

If you are looking for performance (IndexOf twice can be a bit slow) and generalization
(when myList is not necessary List<T> but IEnumerable<T> only) you can put it as
bool proceed = false;
MyClass lastItem = default;
foreach (var item in myList) {
if (!proceed) {
if (proceed = item == listItem)
lastItem = anotherListItem;
else if (proceed = item == anotherListItem)
lastItem = listItem;
}
if (proceed) {
//TODO: do staff here
if (item == lastItem)
break;
}
}

You iterate three times over the list: Two times in IndexOf, and then once again in your loop. You can make your code more efficient with this code, which iterates only once over the list.
privat void MyFunction(MyClass listItem, MyClass anotherListItem)
{
bool betweenTwoItems = false;
foreach(var item in myList)
{
if(item == listItem || item == anotherListItem)
{
betweenTwoItems = !betweenTwoItems;
if(!betweenTwoItems)
{
break;
}
}
if(betweenTwoItems )
{
// do stuff
}
}
}
We set a bool variable if we are between the two items. In the beginning, it is false. The we iterate over the list and check whether the current item is one of the two method parameters. If this is the case, we invert the value of the bool. If after the inversion of the bool the value is false, we can leave the list. After that, we check whether the bool is true. If so, we can do stuff.
Online demo: https://dotnetfiddle.net/xYcr7V

More generic version of the same idea. So this can be created as extension method for IEnumerable<,>
public static IEnumerable<T> RangeOf<T>(this IEnumerable<T> elements, T el1, T el2,
IEqualityComparer<T> comparer = null)
{
comparer ??= EqualityComparer<T>.Default;
var hasStarted = false;
var end = default;
foreach (T el in elements)
{
if (!hasStarted)
{
hasStarted = comparer.Equals(el, el1) || comparer.Equals(el, el2);
end = comparer.Equals(el, el1) ? el2 : el1;
}
if (hasStarted)
yield return el;
if (comparer.Equals(el, end))
yield break;
}
}
and version with the while loop supporting ranges from el to el. For example for [5, 0, 1, 2, 0, 6] the range [0, 0] will be [0, 1, 2, 0]:
public static IEnumerable<T> RangeOf<T>(this IEnumerable<T> elements, T el1, T el2,
IEqualityComparer<T> comparer = null)
{
comparer ??= EqualityComparer<T>.Default;
var hasStarted = false;
var end = default;
var it = elements.GetEnumerator();
while (!hasStarted && it.MoveNext())
{
T el = it.Current;
hasStarted = comparer.Equals(el , el1) || comparer.Equals(el , el2);
end = comparer.Equals(it.Current, el1) ? el2 : el1;
}
if (hasStarted)
yield return it.Current;
while (it.MoveNext())
{
yield return it.Current;
if (comparer.Equals(it.Current, end))
yield break;
}
}
both can be used like this
foreach (var el in list.RangeOf(listItem, anotherListItem))
// Do with el whatever you want to do

Is the list sorted? The you can use that fact to realize which item must be first. Nevertheless you can do with one for-loop, if you prefer:
private static void MyFunction(string item1, string item2)
{
List<string> input = new() {"A", "B", "C", "D", "E"};
int index1 = input.IndexOf(item1);
int index2 = input.IndexOf(item2);
int beginIndex = Math.Min(index1, index2);
int count = Math.Abs(index1 - index2) + 1;
foreach (string item in input.GetRange(beginIndex, count))
{
Console.Write(item);
}
}

Your existing solution can be improved:
int listItemIdx = myList.IndexOf(listItem);
int anotherListItemIdx = myList.IndexOf(anotherListItem);
int startIdx = Math.Min(listItemIdx, anotherListItemIdx);
int endIdx = Math.Max(listItemIdx, anotherListItemIdx);
for(int i = startIdx ; i <= endIdx ; i++)
{
// do stuff
}
Thus, the code duplication disappears and only a minor refactoring is required.
To create a range-loop version, you can create a subset using GetRange(), something like:
int listItemIdx = myList.IndexOf(listItem);
int anotherListItemIdx = myList.IndexOf(anotherListItem);
int startIdx = Math.Min(listItemIdx, anotherListItemIdx);
int endIdx = Math.Max(listItemIdx, anotherListItemIdx);
var subset = myList.GetRange(startIdx, endIdx - startIdx);
foreach(var item in subset)
{
// do stuff
}
Thus, filtering the list and processing the list can now be separated.

Related

Create a list of all permutation from different lists [duplicate]

This one should not be too hard but my mind seems to be having a stack overflow (huehue). I have a series of Lists and I want to find all permutations they can be ordered in. All of the lists have different lengths.
For example:
List 1: 1
List 2: 1, 2
All permutations would be:
1, 1
1, 2
In my case I don't switch the numbers around. (For example 2, 1)
What is the easiest way to write this?
I can't say if the following is the easiest way, but IMO it's the most efficient way. It's basically a generalized version of the my answer to the Looking at each combination in jagged array:
public static class Algorithms
{
public static IEnumerable<T[]> GenerateCombinations<T>(this IReadOnlyList<IReadOnlyList<T>> input)
{
var result = new T[input.Count];
var indices = new int[input.Count];
for (int pos = 0, index = 0; ;)
{
for (; pos < result.Length; pos++, index = 0)
{
indices[pos] = index;
result[pos] = input[pos][index];
}
yield return result;
do
{
if (pos == 0) yield break;
index = indices[--pos] + 1;
}
while (index >= input[pos].Count);
}
}
}
You can see the explanation in the linked answer (shortly it's emulating nested loops). Also since for performace reasons it yields the internal buffer w/o cloning it, you need to clone it if you want store the result for later processing.
Sample usage:
var list1 = new List<int> { 1 };
var list2 = new List<int> { 1, 2 };
var lists = new[] { list1, list2 };
// Non caching usage
foreach (var combination in lists.GenerateCombinations())
{
// do something with the combination
}
// Caching usage
var combinations = lists.GenerateCombinations().Select(c => c.ToList()).ToList();
UPDATE: The GenerateCombinations is a standard C# iterator method, and the implementation basically emulates N nested loops (where N is the input.Count) like this (in pseudo code):
for (int i0 = 0; i0 < input[0].Count; i0++)
for (int i1 = 0; i1 < input[1].Count; i1++)
for (int i2 = 0; i2 < input[2].Count; i2++)
...
for (int iN-1 = 0; iN-1 < input[N-1].Count; iN-1++)
yield { input[0][i0], input[1][i1], input[2][i2], ..., input[N-1][iN-1] }
or showing it differently:
for (indices[0] = 0; indices[0] < input[0].Count; indices[0]++)
{
result[0] = input[0][indices[0]];
for (indices[1] = 0; indices[1] < input[1].Count; indices[1]++)
{
result[1] = input[1][indices[1]];
// ...
for (indices[N-1] = 0; indices[N-1] < input[N-1].Count; indices[N-1]++)
{
result[N-1] = input[N-1][indices[N-1]];
yield return result;
}
}
}
Nested loops:
List<int> listA = (whatever), listB = (whatever);
var answers = new List<Tuple<int,int>>;
for(int a in listA)
for(int b in listB)
answers.add(Tuple.create(a,b));
// do whatever with answers
Try this:
Func<IEnumerable<string>, IEnumerable<string>> combine = null;
combine = xs =>
xs.Skip(1).Any()
? xs.First().SelectMany(x => combine(xs.Skip(1)), (x, y) => String.Format("{0}{1}", x, y))
: xs.First().Select(x => x.ToString());
var strings = new [] { "AB", "12", "$%" };
foreach (var x in combine(strings))
{
Console.WriteLine(x);
}
That gives me:
A1$
A1%
A2$
A2%
B1$
B1%
B2$
B2%
I made the following IEnumerable<IEnumerable<TValue>> class to solve this problem which allows use of generic IEnumerable's and whose enumerator returns all permutations of the values, one from each inner list. It can be conventiently used directly in a foreach loop.
It's a variant of Michael Liu's answer to IEnumerable and Recursion using yield return
I've modified it to return lists with the permutations instead of the single values.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Permutation
{
public class ListOfListsPermuter<TValue> : IEnumerable<IEnumerable<TValue>>
{
private int count;
private IEnumerable<TValue>[] listOfLists;
public ListOfListsPermuter(IEnumerable<IEnumerable<TValue>> listOfLists_)
{
if (object.ReferenceEquals(listOfLists_, null))
{
throw new ArgumentNullException(nameof(listOfLists_));
}
listOfLists =listOfLists_.ToArray();
count = listOfLists.Count();
for (int i = 0; i < count; i++)
{
if (object.ReferenceEquals(listOfLists[i], null))
{
throw new NullReferenceException(string.Format("{0}[{1}] is null.", nameof(listOfLists_), i));
}
}
}
// A variant of Michael Liu's answer in StackOverflow
// https://stackoverflow.com/questions/2055927/ienumerable-and-recursion-using-yield-return
public IEnumerator<IEnumerable<TValue>> GetEnumerator()
{
TValue[] currentList = new TValue[count];
int level = 0;
var enumerators = new Stack<IEnumerator<TValue>>();
IEnumerator<TValue> enumerator = listOfLists[level].GetEnumerator();
try
{
while (true)
{
if (enumerator.MoveNext())
{
currentList[level] = enumerator.Current;
level++;
if (level >= count)
{
level--;
yield return currentList;
}
else
{
enumerators.Push(enumerator);
enumerator = listOfLists[level].GetEnumerator();
}
}
else
{
if (level == 0)
{
yield break;
}
else
{
enumerator.Dispose();
enumerator = enumerators.Pop();
level--;
}
}
}
}
finally
{
// Clean up in case of an exception.
enumerator?.Dispose();
while (enumerators.Count > 0)
{
enumerator = enumerators.Pop();
enumerator.Dispose();
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
You can use it directly in a foreach like this:
public static void Main(string[] args)
{
var listOfLists = new List<List<string>>()
{
{ new List<string>() { "A", "B" } },
{ new List<string>() { "C", "D" } }
};
var permuter = new ListOfListsPermuter<string>(listOfLists);
foreach (IEnumerable<string> item in permuter)
{
Console.WriteLine("{ \"" + string.Join("\", \"", item) + "\" }");
}
}
The output:
{ "A", "C" }
{ "A", "D" }
{ "B", "C" }
{ "B", "D" }

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++;
}

Unknown number for loops using Recursion

I have done some research prior to and have found some great articles but I can't seem to tailor any of the solutions for my given problem. From the research done, I believe the best method of going about this problem would be to use recursion. I have made an example using some generic classes but essentially my problem is I have approximately 10 classes that I can have in a list. I might have only one of these classes and I might have all ten. I am ultimately finding the best combination of "items" (which all inherit from item) for a given problem. I think this would be fairly easy except for I have to deal with creating the combinations before each test.
Below is some sample code using only two classes. If recursion is not the best way to approach this problem then please correct as needed. How might I convert this to be used for any number of items that are needed to test with?
Edited: As some have pointed out my example code is the iterative solution however it is only useful if I have two items. Therefore, I need to define a recursive function to solve the problem based upon the number of for loops needed upon runtime.
-Chance
Research:
C#: N For Loops
Arbitrary number of nested-loops?
Number of nested loops at runtime
static void Main(string[] args)
{
List<Item> myItem = new List<Item>();
int numberItem1 = 0, numberItem2 = 0;
foreach (var item in myItem)
{
if (item.GetType() == typeof(Item1))
{
numberItem1++;
}
else if (item.GetType() == typeof(Item2))
{
numberItem2++;
}
}
List<Item> testingItems = new List<Item>();
//FirstItem
for (int a = 0; a < numberItem1; a++)
{
for (int b = 0; b <= a; b++)
{
testingItems.Add(new Item1 { });
}
//DoTest()
testingItems.Clear();
//Second Item
for (int c = 0; c < numberItem2; c++)
{
for (int d = 0; d <= a ; d++)
{
testingItems.Add(new Item1 { });
}
for (int e = 0; e <= c; e++)
{
testingItems.Add(new Item2 { });
}
//DoTest()
testingItems.Clear();
}
}
}
Non-recursive solution.
IEnumerable<List<Item>> TestLists(List<Item> fullList)
{
List<Type> types = fullList.Select(i => i.GetType()).Distinct().ToList();
List<Item> testList = new List<Item> { (Item)Activator.CreateInstance(types[0]) };
yield return testList;
bool finished = false;
while (!finished)
{
bool incremented = false;
int i = 0;
while (i < types.Count && !incremented)
{
if (testList.Where(t => t.GetType() == types[i]).Count() <
fullList.Where(t => t.GetType() == types[i]).Count())
{
testList.Add((Item)Activator.CreateInstance(types[i]));
incremented = true;
}
else
{
testList = testList.Where(t => t.GetType() != types[i]).ToList();
i++;
}
}
if (incremented)
{
yield return testList;
}
else
{
finished = true;
}
}
}
Usage:
foreach (var partList in TestLists(myListToTest))
{
DoTest(partList);
}
I think the following should work.
This requires you to build a stack of the item types you want to test, and a stack of the number of each present in the original list, with the two stacks in sync with each other.
The input List parameter should be an empty list.
void RecursiveTest(List<Item> testingItems, Stack<Type> itemTypes, Stack<int> itemCounts)
{
if (itemTypes.Count == 0) { return; }
Type thisType = itemTypes.Pop();
int thisCount = itemCounts.Pop();
List<Item> addedItems = new List<Item>();
for (int i = 0; i <= thisCount; i++)
{
if (i > 0)
{
Item thisItem = (Item)Activator.CreateInstance(thisType);
testingItems.Add(thisItem);
addedItems.Add(thisItem);
}
if (itemTypes.Count == 0)
{
DoTest(testingItems);
}
else
{
RecursiveTest(testingItems, itemTypes, itemCounts);
}
}
foreach(Item addedItem in addedItems)
{
testingItems.Remove(addedItem);
}
itemTypes.Push(thisType);
itemCounts.Push(thisCount);
}
Note: This code doesn't output/test lists that don't contain at least one of each item type.
Second note: This now includes the missing cases. It will, however, also test the empty list.
EDIT
This code should generate all the possible test permutations for the list of items + the maximum number of each item that should appear in each test.
EXAMPLE: myItem = Item1 Item1 Item2 Item2 Item3
tests = 1,0,0; 2,0,0; 0,1,0; 1,1,0; 2,1,0; 0,2,0; 1,2,0; 2,2,0; 0,0,1; 1,0,1; 2,0,1; 0,1,1; 1,1,1; 2,1,1; 0,2,1; 1,2,1; 2,2,1
List<Item> myItem = new List<Item>();
List<Type> myOrder = new List<Item>();
Dictionary<Type, int> myCount = new Dictionary<Type, int>();
foreach (var item in myItem)
{
if (myCount.ContainsKey(item.GetType()))
{
myCount[item.GetType()]++;
}
else
{
myOrder.Add(item.GetType());
myCount.Add(item.GetType(), 1);
}
}
List<Item> testingItems = new List<Item>();
int[] testingCounts = new int[myCount.Count];
while(IncrementCounts(testingCounts, myOrder, myCount)) {
for(int x=0; x<testingCounts.length; x++) {
AddInstances( testingItems, myOrder[x], testingCounts[x] );
}
// doTest()
testingItems.Clear();
}
// count permutations using the maxima
// EXAMPLE: maxima [2, 2, 2]
// 1,0,0; 2,0,0; 0,1,0; 1,1,0; 2,1,0; 0,2,0; 1,2,0; 2,2,0; 0,0,1; 1,0,1; 2,0,1 etc..
public static bool IncrementCounts(int[] counts, List<Type> order, Dictionary<Type, int> maxima) {
for(int x=0; x<counts.length; x++) {
if(counts[x] + 1 <= maxima[order[x]]) {
counts[x]++;
return true;
} else {
counts[x] = 0;
}
}
return false; // overflow, so we're finished
}
public static void AddIstances(List<Item> list, Type type, int count) {
for(int x=0; x<count; x++) {
list.Add( Convert.ChangeType( Activator.CreateInstance(type), type ) );
}
}
Please note the above code was written inside the browser window and is untested, so syntax errors may exist.

Creating multiple array using a foreach loop and a select statement

I have a database that I call select all of its contents of a table. It has 18000+ items. I have a method uses a web service that can have an array of up to ten element pass into it. Right now I am doing item by item instead of by an array. I want to create an array of ten and then call the function. I could make an array of ten and then call the function be what is I have an extra three records?
public static void Main()
{
inventoryBLL inv = new inventoryBLL();
DataSet1.sDataTable dtsku = inv.SelectEverything();
foreach (DataSet1.Row row in dtsku)
{
webservicefunction(row.item);
}
}
My question is how would I transform this?
Generic solution of your problem could look like this:
static class LinqHelper
{
public static IEnumerable<T[]> SplitIntoGroups<T>(this IEnumerable<T> items, int N)
{
if (items == null || N < 1)
yield break;
T[] group = new T[N];
int size = 0;
var iter = items.GetEnumerator();
while (iter.MoveNext())
{
group[size++] = iter.Current;
if (size == N)
{
yield return group;
size = 0;
group = new T[N];
}
}
if (size > 0)
yield return group.Take(size).ToArray();
}
}
So your Main function become
public static void Main()
{
inventoryBLL inv = new inventoryBLL();
DataSet1.sDataTable dtsku = inv.SelectEverything();
foreach (var items in dtsku.Select(r => r.item).SplitIntoGroups(10))
{
webservicefunction(items);
}
}
var taken = 0;
var takecount = 10;
while(list.Count() >= taken)
{
callWebService(list.Skip(taken).Take(takecount));
taken += takecount;
}
Generic Extension Method version:
public static void AtATime<T>(this IEnumerable<T> list, int eachTime, Action<IEnumerable<T>> action)
{
var taken = 0;
while(list.Count() >= taken)
{
action(list.Skip(taken).Take(eachTime));
taken += eachTime;
}
}
Usage:
inv.SelectEverything().AtATime<Row>(10, webservicefunction);

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