In my Rx code, I'm using GroupBy to create an IObservable<IGroupedObservable<T>>. From there I am looking to perform some transformations on the IGroupedObservable, while maintaining knowledge of the group (Key).
For example,
IObservable<IGroupedObservable<T>> CreateGroup(this IObservable<T> obs)
{
return obs.GroupBy(o => o.Something);
}
IGroupedObservable<A> Foo(this IGroupedObservable<T> obs)
{
return obs.Select(o => new A(o));
}
IGroupedObservable<B> Bar(this IGroupedObservable<A> obs)
{
return obs.Select(o => new B(o));
}
IObservable<IGroupedObservable<B>> stillGrouped = initialObservable.CreateGroup().Select(grouped => grouped.Foo().Bar());
Of course I can't do this, because the Select() in Foo loses the IGroupedObservable-ness.
Has anyone seen any solutions to this?
EDIT TLDR I'm trying to compose operations that depend on an observable already being grouped, and I'd like the type system to enforce this for me. I suppose I could make these operations take the group Key, and perform a Where on that Key up front, but that's messier and slower.
Hmm.
One brute force way is to replicate the observable methods you need. Something like this:
private class GroupedObservable<TKey, TElement> : IGroupedObservable<TKey, TElement>
{
private readonly IObservable<TElement> _o;
private readonly TKey _k;
public TKey Key { get { return _k } }
public GroupedObservable(TKey key, IObservable<TElement> o)
{
_key = key;
_o = ;
}
public IDisposable Subscribe(IObserver<TElement> observer) { return _o.Subscribe(observer); }
}
public static IGroupedObservable<TKey, TResult> Select<TKey, TSource, TResult>(this IGroupedObservable<TKey, TSource> source, Func<TSource, TResult> selector)
{
return new GroupedObservable<TKey, TResult>(source.Key, ((IObservable<TSource>)source).Select(selector));
}
Over time you'll build up a library of the methods you need.
Another simpler way is to just use Select to transform your IGroupedObservable<TKey, TElement> into IObservable<KeyValuePair<TKey, TElement>>:
public static IObservable<KeyValuePair<TKey, TValue>> ToKV<TKey, TValue>(this IGroupedObservable<TKey, TValue> g)
{
return g.Select(v => new KeyValuePair<TKey, TValue>(g.Key, v));
}
initialObservable.CreateGroup().Select(group => group.ToKV());
Related
I want to create a new class that will wrap the current .net ConcurrentDictionary so that the Add delegate of the GetOrAdd\AddOrUpdate will be ensured to be called only once. I've seen a couple of solutions on the net and the main one is to wrap the TValue with lazy so that many lazy items may be added but only one will survive and invoke it's value factory.
here is what I come up with:
public class LazyConcurrentDictionary<TKey, TValue>
{
private readonly ConcurrentDictionary<TKey, Lazy<TValue>> concurrentDictionary;
public LazyConcurrentDictionary()
{
this.concurrentDictionary = new ConcurrentDictionary<TKey, Lazy<TValue>>();
}
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
{
var lazyResult = this.concurrentDictionary.GetOrAdd(key, k => new Lazy<TValue>(() => valueFactory(k), LazyThreadSafetyMode.ExecutionAndPublication));
return lazyResult.Value;
}
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addFactory, Func<TKey, TValue> updateFactory)
{
// this one fails with "Cannot convert lambda expression to type 'System.Lazy' because it is not a delegate type"
var lazyResult = this.concurrentDictionary.AddOrUpdate(key, (k) => new Lazy<TValue>( () => addFactory(k), LazyThreadSafetyMode.ExecutionAndPublication), updateFactory);
return lazyResult.Value;
}
}
My issue is with the AddOrUpdate signature, I get "Cannot convert lambda expression to type 'System.Lazy' because it is not a delegate type"
What am I doing wrong?
I think you missunderstood meaning of the updateFactory for this function. It is function from TKey,TValue to TValue, not from TKey to TValue, it should calculate an updated value from an old one.
So right syntax should perhaps be like:
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addFactory,
Func<TValue, TValue> updateFactory)
{
var lazyResult = this.concurrentDictionary.AddOrUpdate(key,
(k) => new Lazy<TValue>(() => addFactory(k),
LazyThreadSafetyMode.ExecutionAndPublication),
(k,v)=>new Lazy<TValue>(()=>updateFactory(v.Value)))
);
return lazyResult.Value;
}
Or even (depending on how do you wnat to use it):
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addFactory,
Func<TKey, TValue, TValue> updateFactory)
{
var lazyResult = this.concurrentDictionary.AddOrUpdate(key,
(k) => new Lazy<TValue>(() => addFactory(k), LazyThreadSafetyMode.ExecutionAndPublication),
(k,v)=>new Lazy<TValue>(()=>updateFactory(k, v.Value))
);
return lazyResult.Value;
}
Can someone please help with the following... it's driving me nuts...
// Three methods, virtually identical with the exception of the select field
public IEnumerable<int> GetBrandID()
{
return myData.Select(m => m.BrandID).Distinct();
}
public IEnumerable<int> GetModelID()
{
return myData.Select(m => m.ModelID).Distinct();
}
public IEnumerable<int> GetVehicleID()
{
return myData.Select(m => m.VehicleID).Distinct();
}
// How to create one method which returns the type specified in the parameter??
public IEnumerable<int> GetData(??? myType)
{
return myData.Select(m => myType).Distinct();
}
It sounds like you probably just want a Func<Model, int> parameter:
public IEnumerable<int> GetData(Func<Model, int> projection)
{
return myData.Select(projection).Distinct();
}
You could then have:
var modelIds = GetData(m => m.ModelID);
var vehicleIds = GetData(m => m.VehicleID);
Is that what you're after? (That's assuming myData is an IEnumerable<Model>. If it's an IQueryable<Model> you may want to accept Expression<Func<Model, int>> instead.)
It's not clear what you're exactly after. Maybe something like this?
public static IEnumerable<TResult> GetData<TModel, TResult> (this IEnumerable<TModel> enumerable, Func<TModel, TResult> projection)
{
return enumerable.Select(projection);
}
And than just call like this:
var ints = myData.GetData<MyModel,int>(m=>m.ModelID).Distinct();
var doubles = myData.GetData<MyModel,double>(m=>m.DoubleProp).Distinct();
etc...
public ICollection<T> FindAllWhere(Expression<Func<T, bool>> selectSelector)
{
ICollection<T> elements = EntitySet.Select(selectSelector).ToList().Distinct();
return elements;
}
I have a dictionary where the key is a Tuple where the first item is a Date and the second item is a string. I would like the dictionary to be case insensitive.
I know that if the key was just a string I could pass StringComparer.OrdinalIgnoreCase as a parameter when declaring the dictionary, but this does not seem to work when the key is a Tuple.
Is there some way to specify the StringComparer to use on the second item of the Tuple?
Thanks
Use this overload of the Dictionary constructor, which allows you to specify a custom comparer for the keys. You would accompany this with creating a class that implements
IEqualityComparer<Tuple<string, DateTime>>
Which might look like this:
class CustomEqualityComparer : IEqualityComparer<Tuple<string, DateTime>>
{
public bool Equals(Tuple<string, DateTime> lhs, Tuple<string, DateTime> rhs)
{
return
StringComparer.CurrentCultureIgnoreCase.Equals(lhs.Item1, rhs.Item1)
&& lhs.Item2 == rhs.Item2;
}
public int GetHashCode(Tuple<string, DateTime> tuple)
{
return StringComparer.CurrentCultureIgnoreCase.GetHashCode(tuple.Item1)
^ tuple.Item2.GetHashCode();
}
}
There are no argument checks here, so please don't treat this as production code. Also, care needs to be taken so that the Equals and GetHashCode implementations satisfy the all-important condition that if two tuples compare equal, they must have the same hash code. When dealing with custom text comparisons it is easy to introduce bugs if not extra careful: for example, using ToLowerInvariant instead of ToLower above would be a bug (albeit one that might not surface for some time).
I needed this in a Dictionary<Tuple<>> wrapper, so I used #Jon 's code to create a generic version
public class TupleEqualityComparer<T1, T2> : IEqualityComparer<Tuple<T1, T2>>
{
private IEqualityComparer<T1> comparer1;
private IEqualityComparer<T2> comparer2;
public TupleEqualityComparer(IEqualityComparer<T1> comparer1, IEqualityComparer<T2> comparer2)
{
this.comparer1 = comparer1 ?? EqualityComparer<T1>.Default;
this.comparer2 = comparer2 ?? EqualityComparer<T2>.Default;
}
public bool Equals(Tuple<T1, T2> lhs, Tuple<T1, T2> rhs)
{
return comparer1.Equals(lhs.Item1, rhs.Item1) && comparer2.Equals(lhs.Item2, rhs.Item2);
}
public int GetHashCode(Tuple<T1, T2> tuple)
{
return comparer1.GetHashCode(tuple.Item1) ^ comparer2.GetHashCode(tuple.Item2);
}
}
public class Dictionary<TKey1, TKey2, TValue> : Dictionary<Tuple<TKey1, TKey2>, TValue>()
{
public Dictionary() : base() { }
public Dictionary(IEqualityComparer<TKey1> comparer1, IEqualityComparer<TKey2> comparer2) : base(new TupleEqualityComparer<TKey1, Tkey2>(comparer1, comparer2) { }
public TValue this[TKey1 key1, TKey2 key2]
{
get { return base[Tuple.Create(key1, key2)]; }
}
public void Add(TKey1 key1, TKey2 key2, TValue value)
{
base.Add(Tuple.Create(key1, key2), value);
}
public bool ContainsKey(TKey1 key1, TKey2 key2)
{
return base.ContainsKey(Tuple.Create(key1, key2));
}
public bool TryGetValue(TKey1 key1, TKey2 key2, out TValue value)
{
return base.TryGetValue(Tuple.Create(key1, key2), out value);
}
}
Usage
var dict = new Dictionary<string, DateTime, int>(
StringComparer.OrdinalIgnoreCase, null);
dict.Add("value1", DateTime.Now, 123);
Assert.IsTrue(dict.ContainsKey("VALUe1"));
Since the comparisons are going to be case-insensitive, you could use the toLower/toUpper method in the string side when making the tuples, and then always lower or upper the strings you'll have in the tuples used to retrive/compare entries in the dictionary.
I would like to create an extension method that will allow me to call ToSerializableDictionary(p => p.ID) instead of .ToDictionary(p => p.ID) in the following LINQ context. Though I'm not sure what class i'm supposed to be making an extension method for to replace ToDictionary<T>.
response.attributes = (
from granuleGroup in groups
let granuleRow = granuleGroup.First().First()
select new USDAttributes()
{
id = (int)granuleRow["id"],
...
attributes =
(
...
).ToDictionary(p => p.ID) <--** LINE IN QUESTION **
}
).ToList();
My SerializableDictionary class taken from here is so that I may serialize dictionary objects in my webservice to return hash tables that play nice with JSON.
Initially I was creating an extension method for IDictionary so I can do something like this: ...).ToDictionary(p => p.ID).ToSerializableDictionary(); But this has been a complete failure because it's my first time creating extension methods and I don't know what I'm doing.
public static class CollectionExtensions
{
public static SerializableDictionary<string, object> ToSerializableDictionary(this IDictionary<string,object> sequence)
{
SerializableDictionary<string, object> sDic = new SerializableDictionary<string, object>();
foreach (var item in sequence)
{
}
return sDic;
}
}
public static SerializableDictionary<TKey, T> ToSerializableDictionary<TKey, T>(this IEnumerable<T> seq, Func<T, TKey> keySelector)
{
var dict = new SerializableDictionary<TKey, T>();
foreach(T item in seq)
{
TKey key = keySelector(item);
dict.Add(key, item);
}
return dict;
}
Actually the class you provided has a handy constructor for doing this, so you can actually do
attributes = new SerializableDictionary( (
...
).ToDictionary(p => p.ID) );
But here you go with the extension method (again using that constructor):
public static partial class Extension {
public static SerializableDictionary<T, Q> ToSerializableDictionary(
this IDictionary<T, Q> d) {
return new SerializableDictionary(d);
}
}
Lee's response is the correct answer but just to offer another approach you could try this slightly terser version:
public static SerializableDictionary<TKey, T> ToSerializableDictionary<TKey, T>(this IEnumerable<T> seq, Func<T, TKey> keySelector)
{
var dict = seq.ToDictionary(keySelector);
//since SerializableDictionary can accept an IDictionary
return new SerializableDictionary<TKey, T>(dict);
}
Personally however I'd consider an even simpler approach and use JSON.Net for this task - it works perfectly, is ridiculously simple to use and is incredibly fast. I believe Microsoft have even switched to using JSON.Net in MVC3 (or perhaps 4?) for these reasons. Heartily recommended
I want to run through an IObservable<T> looking for an element that matches a predicate, and if not found, return the last element of the IObservable<T>. I don't want to have to store the entire contents of the IObservable<T>, and I don't want to loop through the IObservable twice, so I've set up an extension method
public static class ObservableExtensions
{
public static IObservable<T> FirstOrLastAsync<T>(this IObservable<T> source, Func<T, bool> pred)
{
return Observable.Create<T>(o =>
{
var hot = source.Publish();
var store = new AsyncSubject<T>();
var d1 = hot.Subscribe(store);
var d2 = hot.FirstAsync(x => pred(x)).Amb(store).Subscribe(o);
var d3 = hot.Connect();
return new CompositeDisposable(d1, d2, d3);
});
}
public static T FirstOrLast<T>(this IObservable<T> source, Func<T, bool> pred)
{
return source.FirstOrLastAsync(pred).Wait();
}
}
The Async method creates a hot observable from a potentially cold one passed in. It subscribes an AsyncSubject<T> to remember the last element, and an IObservable<T> that looks for the element. It then takes the first element from either of those IObservable<T>s, which ever returns a value first via .Amb (AsyncSubject<T> doesn't return a value until it gets an .OnCompleted message).
My questions are the following:
Can this be written better or more concisely using different Observable methods?
Do all of those disposables need to be included in the CompositeDisposable?
When the hot observable is completed without finding a matching element, is there a race condition between FirstAsync throwing an exception, and the AsyncSubject propagating its value?
If so, do I need to change the line to:
var d2 = hot.Where(x => pred(x)).Take(1).Amb(store).Subscribe(o);
I'm pretty new to RX, and this is my first extension on IObservable.
EDIT
I ended up going with
public static class ObservableExtensions
{
public static IObservable<T> FirstOrLastAsync<T>(this IObservable<T> source, Func<T, bool> pred)
{
var hot = source.Publish().RefCount();
return hot.TakeLast(1).Amb(hot.Where(pred).Take(1).Concat(Observable.Never<T>()));
}
public static T FirstOrLast<T>(this IObservable<T> source, Func<T, bool> pred)
{
return source.FirstOrLastAsync(pred).First();
}
}
You could Amb the two cases you want together.
If your source observable is cold, you can do a Publish|Refcount.
public static IObservable<T> FirstOrLast<T>(this IObservable<T> source, Func<T, bool> predicate)
{
return source.TakeLast(1).Amb(source.Where(predicate).Take(1));
}
Test:
var source = Observable.Interval(TimeSpan.FromSeconds(0.1))
.Take(10)
.Publish()
.RefCount();
FirstOrLast(source, i => i == 5).Subscribe(Console.WriteLine); //5
FirstOrLast(source, i => i == 11).Subscribe(Console.WriteLine); //9
I've tried to produce a "simpler" query that works and so far nothing.
If I stick with your basic structure I can offer a slight improvement. Try this:
public static IObservable<T> FirstOrLastAsync<T>(
this IObservable<T> source, Func<T, bool> pred)
{
return Observable.Create<T>(o =>
{
var hot = source.Publish();
var store = new AsyncSubject<T>();
var d1 = hot.Subscribe(store);
var d2 =
hot
.Where(x => pred(x))
.Concat(store)
.Take(1)
.Subscribe(o);
var d3 = hot.Connect();
return new CompositeDisposable(d1, d2, d3);
});
}
It's not hugely better, but I like it better than using Amb. It's just a tad cleaner I think.