How to write this method?
public static IObservable<T> IncreasingSubsequence<T>(this IObservable<T> observable, IComparer<T> comparer)
{
// ???
}
Resulting observable should push only those values that exceed maximum of all previous values.
Another approach would be to use Scan and DistinctUnitChanged. Here's a example using ints for simplicity
IObservable<int> xs;
xs.Scan((last,cur) => cur > last ? cur : last).DistinctUntilChanged()
and the more general form
public static IObservable<T> IncreasingSubsequence<T>(this IObservable<T> xs, IComparer<T> comp)
{
return xs.Scan((last,cur) => comp.Compare(cur, last) == 1 ? cur : last)
.DistinctUntilChanged();
}
I think the easiest way is to use Where() and the fact that closures are mutable:
public static IObservable<T> IncreasingSubsequence<T>(
this IObservable<T> observable, IComparer<T> comparer = null)
{
if (observable == null)
throw new ArgumentNullException("observable");
if (comparer == null)
comparer = Comparer<T>.Default;
T max = default(T);
bool first = true;
return observable.Where(x =>
{
if (first)
{
first = false;
max = x;
return true;
}
if (comparer.Compare(x, max) > 0)
{
max = x;
return true;
}
return false;
});
}
Related
I would like to refactor my method. I also need to get which value was first? So which anyOf? Is it possible to get it from here?
Example:
List<string> anyOf = new List<string>(){"at", "near", "by", "above"};
string source = "South Branch Raritan River near High Bridge at NJ"
public static int IndexOfAny(this string source, IEnumerable<string> anyOf, StringComparison stringComparisonType = StringComparison.CurrentCultureIgnoreCase)
{
var founds = anyOf
.Select(sub => source.IndexOf(sub, stringComparisonType))
.Where(i => i >= 0);
return founds.Any() ? founds.Min() : -1;
}
I would like to get back what is first in string. "near" or "at".
You could use:
public static (int index, string? firstMatch) IndexOfAny(this string source, IEnumerable<string> anyOf, StringComparison stringComparisonType = StringComparison.CurrentCultureIgnoreCase)
{
return anyOf
.Select(s => (Index: source.IndexOf(s, stringComparisonType), String: s))
.Where(x => x.Index >= 0)
.DefaultIfEmpty((-1, null))
.First();
}
I couldn't resist creating a more efficient implementation.
Working here.
Whilst this looks more complicated, its better because,
It allocates only,
an array for the valid search terms,
a array of indices for each search term and,
an array of lengths for each search term.
The source text is enumerated only once and, if a match is found,
that loop will exit early.
Additionally, the code incorporates parameter checking which you'll want as extension methods should be resusable.
public static class Extensions
{
public static int IndexOfAny<T>(
this IEnumerable<T> source,
IEnumerable<IEnumerable<T>> targets,
IEqualityComparer<T> comparer = null)
{
// Parameter Handling
comparer = comparer ?? EqualityComparer<T>.Default;
ArgumentNullException.ThrowIfNull(targets);
var clean = targets
.Where(t => t != null)
.Select(t => t.ToArray())
.Where(t => t.Length > 0)
.ToArray();
if (clean.Length == 0)
{
throw new ArgumentException(
$"'{nameof(targets)}' does not contain a valid search sequence");
}
// Prep
var lengths = clean.Select(t => t.Length).ToArray();
var indices = clean.Select(_ => 0).ToArray();
int i = 0;
// Process
foreach(var t in source)
{
i++;
for(var j = 0; j < clean.Length; j++)
{
var index = indices[j];
if (comparer.Equals(clean[j][index], t))
{
index += 1;
if (index == lengths[j])
{
return i - lengths[j];
}
indices[j] = index;
}
else
{
if (index != 0)
{
indices[j] = 0;
}
}
}
}
return -1;
}
public static int IndexOfAny(
this string source,
IEnumerable<string> targets,
StringComparer comparer = null)
{
comparer = comparer ?? StringComparer.Ordinal;
ArgumentNullException.ThrowIfNull(targets);
return source.ToCharArray().IndexOfAny(
targets.Select(t => t.ToCharArray()),
new CharComparerAdapter(comparer));
}
}
public class CharComparerAdapter : IEqualityComparer<char>
{
private StringComparer Comparer { get; }
public CharComparerAdapter(StringComparer comparer)
{
ArgumentNullException.ThrowIfNull(comparer);
Comparer = comparer;
}
public bool Equals(char left, char right)
{
return Comparer.Equals(left.ToString(), right.ToString());
}
public int GetHashCode(char v)
{
return v;
}
}
I'm new to LINQ. I need to compute new_id as follows:
public class C_Movement
{
public int id=-1;
public static ObservableCollection<C_Movement> list=new ObservableCollection<C_Movement>();
// ...
}
int new_id = (C_Movement.list.Count==0) ? 0 : C_Movement.list.Max(x => x.id)+1;
Is there a LINQ way to compact that expression, so that I don't have to use the ? : structure? The problem is that, when C_Movement.list contains no elements, C_Movement.list.Max(x => x.id) returns null (and I would like it to return -1, instead).
Thank you.
DefaultIfEmpty method should help:
int new_id = C_Movement.list.Select(x => x.id).DefaultIfEmpty(-1).Max()+1;
int new_id = C_Movement.list.Max(x => (int?)x.id).GetValueOrDefault(-1) + 1;
where GetValueOrDefault is a method of Nullable<T>.
How about:
int new_id = 0;
if (C_Movement.list.Any())
new_id = C_Movement.list.Max(x => x.id) + 1;
Try this
public static class LinqExtensions
{
public static TValue Max<TSource, TValue>(this IEnumerable<TSource> source, Func<TSource, TValue> selector, TValue defaultValueIfEmpty)
where TValue : IComparable
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (selector == null)
throw new ArgumentNullException(nameof(selector));
TValue sum;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
return defaultValueIfEmpty;
sum = selector(enumerator.Current);
while (enumerator.MoveNext())
{
var num2 = selector(enumerator.Current);
if (num2.CompareTo(sum) > 0)
sum = num2;
}
}
return sum;
}
public static TSource Max<TSource>(this IEnumerable<TSource> source, TSource defaultValueIfEmpty)
where TSource : IComparable
{
if (source == null)
throw new ArgumentNullException(nameof(source));
TSource sum;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
return defaultValueIfEmpty;
sum = enumerator.Current;
while (enumerator.MoveNext())
{
var num2 = enumerator.Current;
if (num2.CompareTo(sum) > 0)
sum = num2;
}
}
return sum;
}
}
Inspired by
Comparing two collections for equality irrespective of the order of items in them
I created an extension method to test whether two collections are equivalent. To use the extension method, I have to specify two type parameters like this:
IsEquivalentToTestHelper<ObservableCollection<string>, string>(first, second, true);
Is there a way to implement the extension method so that only one generic constraint (e.g. ObservableCollection<string>) need be specified?
UPDATE: Posted the modified code based on answers as an additional response to the question that inspired this one.
Here's my original code:
static public class EnumerableExtensions
{
static public bool IsEquivalentTo<E,T>(this E first, E second) where E : IEnumerable<T>
{
if ((first == null) != (second == null))
return false;
if (!object.ReferenceEquals(first, second) && (first != null))
{
if (first.Count() != second.Count())
return false;
if ((first.Count() != 0) && HaveMismatchedElement<E,T>(first, second))
return false;
}
return true;
}
private static bool HaveMismatchedElement<E,T>(E first, E second) where E : IEnumerable<T>
{
int firstCount;
int secondCount;
var firstElementCounts = GetElementCounts<E,T>(first, out firstCount);
var secondElementCounts = GetElementCounts<E,T>(second, out secondCount);
if (firstCount != secondCount)
return true;
foreach (var kvp in firstElementCounts)
{
firstCount = kvp.Value;
secondElementCounts.TryGetValue(kvp.Key, out secondCount);
if (firstCount != secondCount)
return true;
}
return false;
}
private static Dictionary<T, int> GetElementCounts<E,T>(E enumerable, out int nullCount) where E : IEnumerable<T>
{
var dictionary = new Dictionary<T, int>();
nullCount = 0;
foreach (T element in enumerable)
{
if (element == null)
{
nullCount++;
}
else
{
int num;
dictionary.TryGetValue(element, out num);
num++;
dictionary[element] = num;
}
}
return dictionary;
}
static private int GetHashCode<E,T>(IEnumerable<T> enumerable) where E : IEnumerable<T>
{
int hash = 17;
foreach (T val in enumerable.OrderBy(x => x))
hash = hash * 23 + val.GetHashCode();
return hash;
}
}
static public bool IsEquivalentTo<T>(this IEnumerable<T> first, IEnumerable<T> second)
You could drop the first one and keep the second:
static public bool IsEquivalentTo<T>(this IEnumerable<T> first, IEnumerable<T> second)
You just need to replace every E with IEnumerable<T>, and drop the where statements
For example:
static public bool IsEquivalentTo<T>(this IEnumerable<T> first, IEnumerable<T> second)
var firstElementCounts = GetElementCounts<IEnumerable<T>,T>(first, out firstCount);
static private int GetHashCode<T>(IEnumerable<T> enumerable)
There is the enumerable extension method
Take<TSource>(
IEnumerable<TSource> source,
int count
)
which takes the first count elements from the start.
Is there a way to take the elements from the end?
or even better a way to take the elements from an offset to the end?
Thanks
finiteList.Reverse().Take(count).Reverse();
or
finiteList.Skip(finiteList.Count() - count)
There is some overhead in doing this so a custom method would be better.
Update: A custom method
public static class EnumerableExtensions
{
public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count)
{
if (source == null) throw new ArgumentNullException("source");
if (count < 0) throw new ArgumentOutOfRangeException("count");
if (count == 0) yield break;
var queue = new Queue<T>(count);
foreach (var t in source)
{
if (queue.Count == count) queue.Dequeue();
queue.Enqueue(t);
}
foreach (var t in queue)
yield return t;
}
}
Update: Changed the code a littlebit with ideas from dtb´s answer :-)
Comment to Bear: Look at this example:
var lastFive = Enumerable.Range(1, 10).TakeLast(5);
var lastFive2 = Enumerable.Range(1, 10).TakeLast2(5); //Bear´s way
Queue<int> q = (Queue<int>)lastFive2;
q.Dequeue();
//Is lastFive2 still last five? no...
You could potentially change the values of lastFive2 and therefore that approach can be unsafe or at least it´s not the functional way.
To Bear:
What I meant about safe is this:
var lastFive2 = Enumerable.Range(1, 10).TakeLast2(5); //Bear´s way
//some = Some method which you don't control - it could be from another assembly which represents a crazy plugin etc.
some(lastFive2);
//Now what?
In these cases you would have to make a copy to be sure. But in most cases your way would be fine - and a little bit more efficient than this so +1 :)
An idea is to use a queue which only have internal Enqueue etc.
MoreLINQ provides a TakeLast extension method:
var last10 = finiteList.TakeLast(10);
To take the elements from an offset to the end, Enumerable.Skip should do the trick:
var allFromOffsetToEnd = finiteList.Skip(offset);
#lasseespeholt:
public static class EnumerableExtensions
{
public static ReadOnlyEnumerable<T> AsReadOnly<T>(
this IEnumerable<T> source)
{
return new ReadOnlyEnumerable<T>(source);
}
}
public sealed class ReadOnlyEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerable<T> _source;
public ReadOnlyEnumerable(IEnumerable<T> source)
{
if (_source == null)
{
throw new ArgumentNullException("source");
}
_source = source;
}
public IEnumerator<T> GetEnumerator()
{
return _source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _source.GetEnumerator();
}
}
public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count)
{
if (source == null) throw new ArgumentNullException("source");
if (count < 0) throw new ArgumentOutOfRangeException("count");
if (count == 0)
return Enumerable.Empty<T>();
var queue = new Queue<T>(count);
foreach (var t in source)
{
if (queue.Count == count) queue.Dequeue();
queue.Enqueue(t);
}
return queue.AsReadOnly();
}
A note on performance. Plenty of answers here operating on IEnumerable<> and that is probably what you need and should use.
But if the datasets are large and of type List<> or similar, you can prevent a lot of unnecessary iterating with something like:
// demo, no errorhandling
public static IEnumerable<T> TakeFrom<T>(this IList<T> list, int offset)
{
for (int i = offset; i < list.Count; i += 1)
{
yield return list[i];
}
}
In some of my tests i need to check the order of Lists and do it something like this
DateTime lastDate = new DateTime(2009, 10, 1);
foreach (DueAssigmentViewModel assignment in _dueAssigments)
{
if (assignment.DueDate < lastDate)
{
Assert.Fail("Not Correctly Ordered");
}
lastDate = assignment.DueDate;
}
What i would like to do i turn this into an extension method on IEnumerable to make it reusable.
My inital idea was this
public static bool IsOrderedBy<T, TestType>(this IEnumerable<T> value, TestType initalValue)
{
TestType lastValue = initalValue;
foreach (T enumerable in value)
{
if(enumerable < lastValue)
{
return false;
}
lastValue = value;
}
return true;
}
The ovious problem here is you cant compaire to generic values. Can anyone suggest a way round this.
Cheers
Colin
I think it would make more sense to use a method signature similar to the OrderBy method...
public static bool IsOrderedBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
bool isFirstPass = true;
TSource previous = default(TSource);
foreach (TSource item in source)
{
if (!isFirstPass)
{
TKey key = keySelector(item);
TKey previousKey = keySelector(previous);
if (Comparer<TKey>.Default.Compare(previousKey, key) > 0)
return false;
}
isFirstPass = false;
previous = item;
}
return true;
}
You can then use it like that :
List<Foo> list = new List<Foo>();
...
if (list.IsOrderedBy(f => f.Name))
Console.WriteLine("The list is sorted by name");
else
Console.WriteLine("The list is not sorted by name");
You could add a restraint:
where T:IComparable
Then instead of using the < operator, you could use the CompareTo() method of the IComparable interface.
You should do something like this (I can't see why TestType should be different from T):
public static bool IsOrderedBy<T>(this IEnumerable<T> value, T initalValue)
where T : IComparable<T> {
var currentValue = initialValue;
foreach(var i in value) {
if (i.CompareTo(currentValue) < 0)
return false;
currentValue = i;
}
return true;
}