How do I update/add items in/to an IObservable<int> dynamically? - c#

I have an observable collection to which I want to keep feeding objects and they should reach observers even after someone has subscribed to it (which ofcourse is the main aim of an observable). How do I do it?
In the following program, after the subscription has happened I want to feed in 3 more numbers which should reach observers. How do I do this?
I don't want to go via the route where I implement my own Observable class by implementing IObservable<int> and use Publish method? Is there any other way to achieve this?
public class Program
{
static void Main(string[] args)
{
var collection = new List<double> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var observableCollection = collection.ToObservable();
observableCollection.Subscribe(OnNext);
//now I want to add 100, 101, 102 which should reach my observers
//I know this wont' work
collection.Add(100);
collection.Add(101);
collection.Add(102);
Console.ReadLine();
}
private static void OnNext(double i)
{
Console.WriteLine("OnNext - {0}", i);
}
}

This is what I'd do:
var subject = new Subject<double>();
var collection = new List<double> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var observableCollection = collection
.ToObservable()
.Concat(subject); //at the end of the original collection, add the subject
observableCollection.Subscribe(OnNext);
//now I want to add 100, 101, 102 which should reach my observers
subject.OnNext(100);
subject.OnNext(101);
subject.OnNext(102);
Generally, if you can observe whatever is producing the additional input, you'd want to concat that observable, rather than imperatively pushing these values into a subject, but sometimes that's not practical.

Related

Linq - Performant selection of specific class properties in list

I'm having a class with several material properties (e.g . temperature). The cross section of a sample is represented by a list of class elements.
I only need material properties in multiple methods at specific positions of the cross section or indices, respectively.
At the moment I'm using a Linq-select to first create an IEnumerable of the needed property.
Than I'm creating a list using the IEnumerable, where I can select the wanted elements by index.
Example (indices is a List with :
var indices = new List<int>() {1, 3, 7, 15, 30, 50};
var Ts = microstructures.Select(x => x.T).ToList();
var list = new List<double>();
for (int i = 0; i < indices.Count; i++)
{
list.Add(Ts[indices[i]]);
}
Is there a more efficient way without creating a list to perform this task?
microstructures has < 100 elements, indices ~ 10 and the properties of the microstructure can be complex classes themselves.
You may filter the T directly using the where overload that expose the object and it's index. msdn
Then replace the Select by a Select many to flattern List<List> to List
public class Toto {
public List<int> T { get; set; }
}
var target = new HashSet<int>{ 1, 3, 7, 15, 30, 50 };
var inputs = Enumerable.Range(0, 10) // generate Data Sample
.Select(x=>new Toto
{
T = Enumerable.Range(100*x,100).ToList()
});
var r = inputs.SelectMany(x => x.T.Where((y,i)=> target.Contains(i)));
live Demo

How to assert all items in a collection to be different using fluent-assertions?

I want to make sure that all items in a collection to be different. How to do that?
Let's say:
IEnumerable collection = new[] { 1, 2, 5, 8 };
collection.Should().BeAllDifferent(); // NOTE: BeAllDifferent doesn't exist

Remove Duplicate entries from a 2D list in CSharp

How do I remove duplicate entries from a 2D list in C#.
here is my code.
HashSet<List<int>> set = new HashSet<List<int>>();
set.Add(new List<int>(){1,-2,-1,2});
set.Add(new List<int>(){3,-2,1,1});
set.Add(new List<int>() {1,-2,-1,2}); //duplicate entry
but the result i get from this has the duplicate entry {{1,-2,-1,2},{3,-2,1,1},{1,-2,-1,2}} i also tried using set.Distinct().ToList() but i still get duplicates in my result.
please can someone point me to a neat way to get this done using HashSet. I don't want to compare each sequence in the list because that adds some time complexity to my code.
Thanks for your help in anticipation.
You can write your own implementation of IEqualityComparer<List<int>> (and use a SequenceEqual method for list equality)
public class ListComparer : IEqualityComparer<List<int>>
{
public bool Equals(List<int> x, List<int> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<int> obj)
{
return obj.Aggregate(19, (current, item) => current ^ item.GetHashCode());
}
}
Then pass its instance to Distinct method
var set = new HashSet<List<int>>
{
new List<int>() {1, -2, -1, 2}, new List<int>() {3, -2, 1, 1}, new List<int>() {1, -2, -1, 2}
};
var result = set.Distinct(new ListComparer());
It allows you to remove {1,-2,-1,2} duplicated entry.
You can also pass ListComparer instance to HashSet constructor and get rid of adding a duplicate lists
var set = new HashSet<List<int>>(new ListComparer())
{
new List<int>() {1, -2, -1, 2}, new List<int>() {3, -2, 1, 1}, new List<int>() {1, -2, -1, 2}
};
In example above set will contain only two items without duplicated lists
you can create an implementation of IEqualityComparer and pass it to Distinct function.
in you implementation of IEqualityComparer order the list and check for except (or intersect) if there is any then the two list is not equals.
you can also do a simple loop through each list, and check for item in same index if number of same keys are equal to your list length then eliminate on of them.

SortedList<> and its strange setters

I initially had some code, which when simplified, looks like this:
var planets = new List<Planet>
{
new Planet {Id = 1, Name = "Mercury"},
new Planet {Id = 2, Name = "Venus"},
};
I got into a scenario where the list was being populated all at once, but the reads weren't fast enough. And so, I changed this to use a SortedList instead.
I later realized that I could rewrite it like this
var planets = new SortedList<int, Planet>
{
{1, new Planet {Id = 1, Name = "Mercury"}},
{2, new Planet {Id = 2, Name = "Venus"}},
//in my actual code, i am reading the ids from a db
};
But before I got to this approach, I had the code written like this
var planets = new SortedList<int, Planet>
{
Keys = {1, 2},
Values =
{
new Planet {Id = 1, Name = "Mercury"},
new Planet {Id = 2, Name = "Venus"},
}
};
which gives me this exception
System.NotSupportedException: This operation is not supported on SortedList
nested types because they require modifying the original SortedList.
at System.ThrowHelper.ThrowNotSupportedException(ExceptionResource resource)
at System.Collections.Generic.SortedList`2.KeyList.Add(TKey key)
which I found to be very strange, coz IMHO, I wasn't really modifying the "original SortedList" as it claims, and what "nested types" is it talking about? Is it the list of keys internal to the SortedList?
I see then that the Keys and Values properties in SortedList don't actually have setters. They are read-only properties, and yet, I don't get a compile-time error. I am allowed to make a set call, as I can see in the stack trace with KeyList.Add. I feel the only reason why this fails is because of an explicit check within SortedList, which seems bizarre to me!
For instance
var str = new String {Length = 0}; gives me a compile-time error as expected, since Length is a read-only property, as does planets.Keys = null;
Someone please tell me - what simple fact am I overlooking here?
The code that you've written is comparable to this:
var planets = new SortedList<int, Planet>();
planets.Keys.Add(1);
planets.Keys.Add(2);
planets.Values.Add(new Planet { Id = 1, Name = "Mercury" });
planets.Values.Add(new Planet { Id = 2, Name = "Venus" });
SortedList requires that you add the value and key at the same time via SortedList<TKey, TValue>.Add(TKey key, TValue value) method, so that it can sort the value by the key. The implementation of the IList<T> which is used for Keys and Values internally does not support adding a respective key or value independently via the IList<T>.Add(T value) method.
You should be able to reproduce this error by calling Keys.Add(...) or Values.Add(...)
My initial query about the SortedList has now minimized to this concern about array, collection & object initializers, and the way the compiler interprets them differently. Thanks to #Haney again for the first answer to guide me towards this point of view, and to ILSpy for these insights.
Here are some array and collection initializers:
int[] a = { 1, 2, 3 };
int[] b = new int[] { 1, 2, 3 };
IList<int> c = { 1, 2, 3 };
IList<int> d = new int[] { 1, 2, 3 };
They all look kind of similar. Here, the compiler produces the exact same output for a & b. For c, we will get this compile-time error:
Can only use array initializer expressions to assign to array types.
Try using a new expression instead.
which makes sense since we shouldn't use array initializers for collections. But then, d produces the exact same result as a & b. And I thought that was an array initializer as well. Apparently not.
Now consider this class
class MyCollectionContainer
{
public int[] MyIntArray { get; set; }
public IList<int> MyList { get; set; }
}
and this code that operates on it
var containerA = new MyCollectionContainer { MyIntArray = { 1, 2, 3 } };
var containerB = new MyCollectionContainer { MyIntArray = new int[]{ 1, 2, 3 } };
var containerC = new MyCollectionContainer { MyList = { 1, 2, 3 } };
var containerD = new MyCollectionContainer { MyList = new int[]{ 1, 2, 3 } };
containerA gives this compile-time error:
Cannot initialize object of type 'int[]' with a collection initializer
For containerB, the compiler effectively converts it into this code:
MyCollectionContainer myCollectionContainer = new MyCollectionContainer();
myCollectionContainer.MyIntArray = new int[] {1, 2, 3};
For containerD, its pretty much the same, barring the fact that its another property that gets initialized:
MyCollectionContainer myCollectionContainer = new MyCollectionContainer();
myCollectionContainer.MyList = new int[] {1, 2, 3};
For containerC, the compiler morphs it into:
MyCollectionContainer myCollectionContainer = new MyCollectionContainer();
myCollectionContainer.MyList.Add(1);
myCollectionContainer.MyList.Add(2);
myCollectionContainer.MyList.Add(3);
This results in a run-time NullReferenceException since MyList is not initialized.
This means the only valid ways to initialize the collection container object here is containerB and containerD. To me, this clearly shows that object initializers are different when compared to array & collection initializers, in the way the compiler interprets them.

Executing functions conditionally and in parallel

I have some code that currently looks somewhat like this:
Parallel.Invoke(
MyFunction1,
MyFunction2,
MyFunction3,
MyFunction4,
MyFunction5);
This works really well. Now I also have a list of bytes that's passed in as a parameter and that looks like this:
TheList = new List<Byte>{1, 3, 5, 6 };
I want to execute functions based on the content of that list. Let's say that each value of this list is associated to the execution a certain function, like this:
1: MyFunction1,
2: MyFunction2,
...
6: MyFunction6
The actual names of these functions are different.
How do I change my code so that the function calls get executed in parallel and conditionally to the content of the list of bytes? For instance, if the list contains 1 and 5 then the code will execute only MyFunction1 and MyFunction5, both in parallel.
Thanks.
How about this?
Dictionary<byte, Action> actions = new Dictionary<byte, Action>()
{
{ 1, MyFunction1 },
{ 2, MyFunction2 },
...
{ 6, MyFunction6 }
};
List<byte> actionList = new List<byte>() { 1, 3, 5, 6 };
Parallel.Invoke((from action in actionList select actions[action]).ToArray());

Categories