I need 2 lists which are separate and one list containing the items of these two lists.
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
List<int> list3 = list1 & list2
When I add some integers in list1, I would like them to appear in list3 as well.
I want the same behavior when a new item is added into list2.
A reference of more than one lists.
Is this possible?
No, you can't do that with List<T> directly. However, you could declare:
IEnumerable<int> union = list1.Union(list2);
Now that will be lazily evaluated - every time you iterate over union, it will return every integer which is in either list1 or list2 (or both). It will only return any integer once.
If you want the equivalent but with concatenation, you can use
IEnumerable<int> concatenation = list1.Concat(list2);
Again, that will be lazily evaluated.
As noted in comments, this doesn't expose all the operations that List<T> does, but if you only need to read from the "combined integers" (and do so iteratively rather than in some random access fashion) then it may be all you need.
Is it possible?
Not with List since it's a static data structure - however you could use a query that is the concatenation of the two lists. Then whenever you enumerate the query it will show the current contents:
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
IEnumerable<int> list3 = list1.Concat(list2);
But as soon as you materialize the query into a data structure (by calling ToList, ToArray, etc.) the contents are static and will not update if one of the underlying lists updates.
No. You can create your own custom type that exposes methods similar to what a List<T> does (an indexer, Add, Remove methods, etc.), possibly even implementing IList<T>, but it wouldn't be a List<T>.
public class CompositeList<T> : IList<T>
{
private IList<IList<T>> lists;
public CompositeList(IList<IList<T>> lists)
{
this.lists = lists;
}
public CompositeList(params IList<T>[] lists)
{
this.lists = lists;
}
public int IndexOf(T item)
{
int globalIndex = 0;
foreach (var list in lists)
{
var localIndex = list.IndexOf(item);
if (localIndex >= 0)
return globalIndex + localIndex;
else
globalIndex += list.Count;
}
return -1;
}
public void Insert(int index, T item)
{
//note that there is an ambiguity over where items should be inserted
//when they are on the border of a set of lists.
foreach (var list in lists)
{
//use greater than or equal instead of just greater than to have the inserted item
//go in the later of the two lists in ambiguous situations,
//rather than the former.
if (index > list.Count)
index -= list.Count;
else
{
list.Insert(index, item);
return;
}
}
//TODO deal with having no lists in `lists`
//TODO deal with having only empty lists in `lists`
throw new IndexOutOfRangeException();
}
public void RemoveAt(int index)
{
foreach (var list in lists)
{
if (index > lists.Count)
index -= list.Count;
else
list.RemoveAt(index);
}
throw new IndexOutOfRangeException();
}
public T this[int index]
{
get
{
foreach (var list in lists)
{
if (index > lists.Count)
index -= list.Count;
else
return list[index];
}
throw new IndexOutOfRangeException();
}
set
{
foreach (var list in lists)
{
if (index > lists.Count)
index -= list.Count;
else
list[index] = value;
}
throw new IndexOutOfRangeException();
}
}
public void Add(T item)
{
if (!lists.Any())
lists.Add(new List<T>());
lists[lists.Count - 1].Add(item);
}
public void Clear()
{
foreach (var list in lists)
list.Clear();
}
public bool Contains(T item)
{
return lists.Any(list => list.Contains(item));
}
public void CopyTo(T[] array, int arrayIndex)
{
if (array.Length - arrayIndex - Count < 0)
throw new ArgumentException("The array is not large enough.");
int iterations = Math.Min(array.Length, Count);
for (int i = arrayIndex; i < iterations; i++)
array[i] = this[i];
}
public int Count
{
get { return lists.Sum(list => list.Count); }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
foreach (var list in lists)
{
if (list.Remove(item))
return true;
}
return false;
}
public IEnumerator<T> GetEnumerator()
{
return lists.SelectMany(x => x).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Related
I have created a helper function which accepts a string array as input and the index of the column as selected output.
public static List<T> GetByIndex<T>(string[] data, int index)
{
List<T> list = new List<T>();
foreach (var item in data)
{
if (item.Contains("|"))
{
string[] s = item.Split("|");
list.Add(s[index]);
}
}
return list;
}
At line list.Add(s[index]); i get the error Cannot convert from 'string' to 'T'.
How can i make this method generic?
The function should return string or integer or even maybe boolean
How can i make this method generic?
You shouldn't. You're only dealing with strings so make the method return a List<string>
public static List<string> GetByIndex(string[] data, int index)
{
var list = new List<string>();
foreach (var item in data)
{
if (item.Contains("|"))
{
string[] s = item.Split("|");
list.Add(s[index]);
}
}
return list;
}
If you need to also support int then just make an overload which returns a List<int> and use int.Parse / int.TryParse.
It seems that you don't want generic T at all: what is the expected output for, say, T == IComparer<DateTime>?
I suggest getting rid of T and returning List<string>:
public static List<string> GetByIndex(string[] data, int index) {
// Public method's arguments validation
if (data is null)
throw new ArgumentNullException(nameof(data));
if (index < 0)
throw new ArgumentOutOfRangeException(nameof(index));
List<string> list = new List<string>();
foreach (string item in data) {
// Do not forget about nulls
if (item != null) {
// We can stop earlier on Split:
// if, say, index == 2 we don't want all 12345 items
string[] s = item.Split('|', index + 2);
// s can well be too short
if (s.Length > index)
list.Add(s[index]);
}
}
return list;
}
If you want to return a List<T>, you need to provide some way of converting each string into a T.
Such as:
public static List<T> GetByIndex<T>(
string[] data,
int index,
Func<string, T> convertItem)
{
List<T> list = new List<T>();
foreach (var item in data)
{
if (item.Contains("|"))
{
string[] s = item.Split("|");
list.Add(convertItem(s[index]));
}
}
return list;
}
And you could provide convenience overloads for the types you commonly use.
For example:
public static List<int> GetIntByIndex(string[] data, int index)
{
return GetByIndex(data, index, int.Parse);
}
I'm trying to make extension methods for generic array, so I could takeout random set of elements.
I made following extension methods for List<T> type and they work great, but I can't work out how to do exactly the same for generic array:
public static T Random<T>(this List<T> list)
{
return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}
public static IEquatable Random<IEquatable>(this List<IEquatable> list, List<IEquatable> hits)
{
int rand = GameManager.instance.functions.RandomInt(list.Count - 1);
while (hits.Exists(h => h.Equals(list[rand])))
rand = GameManager.instance.functions.RandomInt(list.Count - 1);
return list[rand];
}
public static List<T> Random<T>(this List<T> list, int count)
{
List<T> result = new List<T>();
for (int i = 0; i < count; i++)
{
result.Add(list.Random());
}
return result;
}
public static List<IEquatable> RandomUnique<IEquatable>(this List<IEquatable> list, int count)
{
List<IEquatable> result = new List<IEquatable>();
for (int i = 0; i < count; i++)
{
result.Add(list.Random(result));
}
return result;
}
I tried to rework the first method like this:
public static IEnumerable Random<IEnumerable>(this IEnumerable list)
but it doesn't recognize list as an array so I can't get to it's length value.
I see a workaround, to do a List from Array, then get my random values and make array again, but it's seems like too much action for just taking eg. 2 random from 4 elements array.
Please advise
EDIT:
Thanks to Mathew in comments, I managed to construct the extension method for generic array correctly:
public static T Random<T>(this T[] list)
{
return list[GameManager.instance.functions.RandomInt(list.Length - 1)];
}
But ultimately I'll play around with the Dmitry's answer and try to make these for IEnumerable. Thank you very much!
EDIT2:
Thanks to Zastai, I changed all methods so they work for both List and generic array:
public static T Random<T>(this IReadOnlyList<T> list)
{
return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}
public static IEquatable Random<IEquatable>(this IReadOnlyList<IEquatable> list, List<IEquatable> hits)
{
int rand = GameManager.instance.functions.RandomInt(list.Count - 1);
while (hits.Exists(h => h.Equals(list[rand])))
rand = GameManager.instance.functions.RandomInt(list.Count - 1);
return list[rand];
}
public static List<T> Random<T>(this IReadOnlyList<T> list, int count)
{
List<T> result = new();
for (int i = 0; i < count; i++)
{
result.Add(list.Random());
}
return result;
}
public static List<IEquatable> RandomUnique<IEquatable>(this IReadOnlyList<IEquatable> list, int count)
{
List<IEquatable> result = new();
for (int i = 0; i < count; i++)
{
result.Add(list.Random(result));
}
return result;
}
Doesn't work for strings (as in "abcdefg".Random()), but for my needs it's not neccessary.
IEnumerable is specifically just a sequence of values, and has no length.
IReadOnlyList on the other hand, is a list of values (so does have a length) and does not allow adding/removing values.
A .NET array implements both.
So if you change your extension methods to take IReadOnlyList<xxx> instead of List<xxx> they should automatically work on arrays too.
Instead of implementing extensions methods for List<T>, T[] etc. you can try implementing a
single routine for IEnumerable<T>, e.g.
public static partial class EnumerableExtensions {
public static T Random<T>(this IEnumerable<T> source) {
//DONE: do not forget to validate public methods' arguments
if (source is null)
throw new ArgumentNullException(nameof(source));
// If enumerable is a collection (array, list) we can address items explictitly
if (source is ICollection<T> collection) {
if (collection.Count <= 0)
throw new ArgumentOutOfRangeException(nameof(source),
$"Empty {nameof(source)} is not supported.");
return collection[GameManager.instance.functions.RandomInt(collection.Count - 1)];
}
// In general case we have to materialize the enumeration
var list = source.ToList();
if (list.Count <= 0)
throw new ArgumentOutOfRangeException(nameof(source),
$"Empty {nameof(source)} is not supported.");
return list[GameManager.instance.functions.RandomInt(list.Count - 1)];
}
}
Then you can use the same extension method with list, array etc.:
// Array
int demo1 = new int[] {4, 5, 6}.Random();
// List
double demo2 = new List<double>() {1.0. 3.0}.Random();
// String is not array or list but implements IEnumerable<char>
char demo3 = "abcdef".Random();
As an alternative to consider: You can use Reservoir sampling to select N items from a sequence of unknown length.
Here's a sample implementation:
/// <summary>Randomly selects n elements from a sequence of items.</summary>
public static List<T> RandomlySelectedItems<T>(IEnumerable<T> items, int n, System.Random rng)
{
// See http://en.wikipedia.org/wiki/Reservoir_sampling for details.
var result = new List<T>(n);
int index = 0;
foreach (var item in items)
{
if (index < n)
{
result.Add(item);
}
else
{
int r = rng.Next(0, index + 1);
if (r < n)
result[r] = item;
}
++index;
}
if (index < n)
throw new ArgumentException("Input sequence too short");
return result;
}
I have
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 1, 2, 4 };
I want from this:
listAdded: {4}
listRemoved: {2}
The elements are distinct.
How can I:
*Quickly find if list1 and list2 are the same (no changes)
*Get the list of changes (added & removed)?
I'm currently using List<T> but I'm open to HashSet<T> if it will make things faster.
Simply by using Except you can get the differences between two lists in a new collection, then you can check the count of the new collection to see if they are any differences.
var removed = list1.Except(list2).ToList();
var added = list2.Except(list1).ToList();
Then you are free to do a simple if on their Count:
bool areDifferent = removed.Count > 0 || added.Count > 0;
or as Kevin suggested:
bool areDifferent = removed.Any() || added.Any();
Pseudocode with LINQ - (removed - see #meJustAndrew's answer for a better LINQ implementation)
You could do something O(n) if the lists are sorted:
int i = 0;
int j = 0;
while(i < list1.Count && j < list2.Count)
{
if (list1[i] == list2[j])
{
++i;
++j;
}
else if (list1[i] < list2[j])
{
removed.Add(list1[i]);
++i;
}
else // if (list1[i] > list2[j])
{
added.Add(list2[j]);
++j;
}
}
if (i < list1.Count)
{
removed.AddRange(list1.GetRange(i,list1.Count));
}
if (j < list2.Count)
{
added.AddRange(list2.GetRange(j,list2.Count));
}
You can make a Class that derives from List<> and override the Add() and Remove().
Public class MyList<T> : List<T>
{
private List<T> oldItems = new List<T>();
private List<T> newItems = new List<T>();
private List<T> items = new List<T>();
public List<T> Items
{
get { return items; }
set { items = value; }
}
public void Add(T value)
{
Items.Add(value);
newItems.Add(Items.Where(w=>w==value)); // must be the object in the "Items" list
}
public void Remove(T value)
{
Items.Remove(value);
oldItems.Add(value); //value does not exist anymore in `Items`
}
public List<T> GetOldItems()
{
List<T> oldi = oldItems;
oldItems.Clear();
return oldi;
}
public List<T> GetNewItems() //
{
List<T> newi = newItems;
newItems.Clear();
return newi;
}
}
Then you have a list with inside a list for both old items and new items.
When you add a item, it will be registered even so if you remove an item.
When you get the new or old items, the register will be cleared.
I have been looking for a way of splitting a foreach loop into multiple parts and came across the following code:
foreach(var item in items.Skip(currentPage * itemsPerPage).Take(itemsPerPage))
{
//Do stuff
}
Would items.Skip(currentPage * itemsPerPage).Take(itemsPerPage) be processed in every iteration, or would it be processed once, and have a temporary result used with the foreach loop automatically by the compiler?
No, it would be processed once.
It's the same like:
public IEnumerable<Something> GetData() {
return someData;
}
foreach(var d in GetData()) {
//do something with [d]
}
The foreach construction is equivalent to:
IEnumerator enumerator = myCollection.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
object current = enumerator.Current;
Console.WriteLine(current);
}
}
finally
{
IDisposable e = enumerator as IDisposable;
if (e != null)
{
e.Dispose();
}
}
So, no, myCollection would be processed only once.
Update:
Please note that this depends on the implementation of the IEnumerator that the IEnumerable uses.
In this (evil) example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
namespace TestStack
{
class EvilEnumerator<T> : IEnumerator<T> {
private IEnumerable<T> enumerable;
private int index = -1;
public EvilEnumerator(IEnumerable<T> e)
{
enumerable = e;
}
#region IEnumerator<T> Membres
public T Current
{
get { return enumerable.ElementAt(index); }
}
#endregion
#region IDisposable Membres
public void Dispose()
{
}
#endregion
#region IEnumerator Membres
object IEnumerator.Current
{
get { return enumerable.ElementAt(index); }
}
public bool MoveNext()
{
index++;
if (index >= enumerable.Count())
return false;
return true;
}
public void Reset()
{
}
#endregion
}
class DemoEnumerable<T> : IEnumerable<T>
{
private IEnumerable<T> enumerable;
public DemoEnumerable(IEnumerable<T> e)
{
enumerable = e;
}
#region IEnumerable<T> Membres
public IEnumerator<T> GetEnumerator()
{
return new EvilEnumerator<T>(enumerable);
}
#endregion
#region IEnumerable Membres
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
class Program
{
static void Main(string[] args)
{
IEnumerable<int> numbers = Enumerable.Range(0,100);
DemoEnumerable<int> enumerable = new DemoEnumerable<int>(numbers);
foreach (var item in enumerable)
{
Console.WriteLine(item);
}
}
}
}
Each iteration over enumerable would evaluate numbers two times.
Question:
Would items.Skip(currentPage * itemsPerPage).Take(itemsPerPage) be
processed every iteration, or would it be processed once, and have a
temporary result used with the foreach loop automatically by the
compiler?
Answer:
It would be processed once, not every iteration. You can put the collection into a variable to make the foreach more readable. Illustrated below.
foreach(var item in items.Skip(currentPage * itemsPerPage).Take(itemsPerPage))
{
//Do stuff
}
vs.
List<MyClass> query = items.Skip(currentPage * itemsPerPage).Take(itemsPerPage).ToList();
foreach(var item in query)
{
//Do stuff
}
vs.
IEnumerable<MyClass> query = items.Skip(currentPage * itemsPerPage).Take(itemsPerPage);
foreach(var item in query)
{
//Do stuff
}
The code that you present will only iterate the items in the list once, as others have pointed out.
However, that only gives you the items for one page. If you are handling multiple pages, you must be calling that code once for each page (because somewhere you must be incrementing currentPage, right?).
What I mean is that you must be doing something like this:
for (int currentPage = 0; currentPage < numPages; ++currentPage)
{
foreach (var item in items.Skip(currentPage*itemsPerPage).Take(itemsPerPage))
{
//Do stuff
}
}
Now if you do that, then you will be iterating the sequence multiple times - once for each page. The first iteration will only go as far as the end of the first page, but the next will iterate from the beginning to the end of the second page (via the Skip() and the Take()) - and the next will iterate from the beginning to the end of the third page. And so on.
To avoid that you can write an extension method for IEnumerable<T> which partitions the data into batches (which you could also describe as "paginating" the data into "pages").
Rather than just presenting an IEnumerable of IEnumerables, it can be more useful to wrap each batch in a class to supply the batch index along with the items in the batch, like so:
public sealed class Batch<T>
{
public readonly int Index;
public readonly IEnumerable<T> Items;
public Batch(int index, IEnumerable<T> items)
{
Index = index;
Items = items;
}
}
public static class EnumerableExt
{
// Note: Not threadsafe, so not suitable for use with Parallel.Foreach() or IEnumerable.AsParallel()
public static IEnumerable<Batch<T>> Partition<T>(this IEnumerable<T> input, int batchSize)
{
var enumerator = input.GetEnumerator();
int index = 0;
while (enumerator.MoveNext())
yield return new Batch<T>(index++, nextBatch(enumerator, batchSize));
}
private static IEnumerable<T> nextBatch<T>(IEnumerator<T> enumerator, int blockSize)
{
do { yield return enumerator.Current; }
while (--blockSize > 0 && enumerator.MoveNext());
}
}
This extension method does not buffer the data, and it only iterates through it once.
Given this extension method, it becomes more readable to batch up the items. Note that this example enumerates through ALL items for all pages, unlike the OP's example which only iterates through the items for one page:
var items = Enumerable.Range(10, 50); // Pretend we have 50 items.
int itemsPerPage = 20;
foreach (var page in items.Partition(itemsPerPage))
{
Console.Write("Page " + page.Index + " items: ");
foreach (var i in page.Items)
Console.Write(i + " ");
Console.WriteLine();
}
I need to sort some objects according to their contents (in fact according to one of their properties, which is NOT the key and may be duplicated between different objects).
.NET provides two classes (SortedDictionary and SortedList), and both are implemented using a binary tree. The only differences between them are
SortedList uses less memory than SortedDictionary.
SortedDictionary has faster insertion and removal operations for unsorted data, O(log n) as opposed to O(n) for SortedList.
If the list is populated all at once from sorted data, SortedList is faster than SortedDictionary.
I could achieve what I want using a List, and then using its Sort() method with a custom implementation of IComparer, but it would not be time-efficient as I would sort the whole List each time I want to insert a new object, whereas a good SortedList would just insert the item at the right position.
What I need is a SortedList class with a RefreshPosition(int index) to move only the changed (or inserted) object rather than resorting the whole list each time an object inside changes.
Am I missing something obvious ?
Maybe I'm slow, but isn't this the easiest implementation ever?
class SortedList<T> : List<T>
{
public new void Add(T item)
{
Insert(~BinarySearch(item), item);
}
}
http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx
Unfortunately, Add wasn't overrideable so I had to new it which isn't so nice when you have List<T> list = new SortedList<T>; which I actually needed to do.... so I went ahead and rebuilt the whole thing...
class SortedList<T> : IList<T>
{
private List<T> list = new List<T>();
public int IndexOf(T item)
{
var index = list.BinarySearch(item);
return index < 0 ? -1 : index;
}
public void Insert(int index, T item)
{
throw new NotImplementedException("Cannot insert at index; must preserve order.");
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
}
public T this[int index]
{
get
{
return list[index];
}
set
{
list.RemoveAt(index);
this.Add(value);
}
}
public void Add(T item)
{
list.Insert(~list.BinarySearch(item), item);
}
public void Clear()
{
list.Clear();
}
public bool Contains(T item)
{
return list.BinarySearch(item) >= 0;
}
public void CopyTo(T[] array, int arrayIndex)
{
list.CopyTo(array, arrayIndex);
}
public int Count
{
get { return list.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
var index = list.BinarySearch(item);
if (index < 0) return false;
list.RemoveAt(index);
return true;
}
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return list.GetEnumerator();
}
}
Or perhaps something like this is a more appropriate Remove function...
public bool Remove(T item)
{
var index = list.BinarySearch(item);
if (index < 0) return false;
while (((IComparable)item).CompareTo((IComparable)list[index]) == 0)
{
if (item == list[index])
{
list.RemoveAt(index);
return true;
}
index++;
}
return false;
}
Assuming items can compare equal but not be equal...
I eventually decided to write it :
class RealSortedList<T> : List<T>
{
public IComparer<T> comparer;
public int SortItem(int index)
{
T item = this[index];
this.RemoveAt(index);
int goodposition=FindLocation(this[index], 0, this.Count);
this.Insert(goodposition, item);
return goodposition;
}
public int FindLocation(T item, int begin, int end)
{
if (begin==end)
return begin;
int middle = begin + end / 2;
int comparisonvalue = comparer.Compare(item, this[middle]);
if (comparisonvalue < 0)
return FindLocation(item,begin, middle);
else if (comparisonvalue > 0)
return FindLocation(item,middle, end);
else
return middle;
}
}
Don't forget that inserting an item into a list backed by an array can be an expensive operation - inserting a bunch of items and then sorting may well be quicker unless you really need to sort after every single operation.
Alternatively, you could always wrap a list and make your add operation find the right place and insert it there.
I've solved this problem in the past by writing an extension method that does a binary search on a IList, and another that does an insert. You can look up the correct implementation in the CLR source because there's a built-in version that works only on arrays, and then just tweak it to be an extension on IList.
One of those "should be in the BCL already" things.
What I need is a SortedList class with
a RefreshPosition(int index) to move
only the changed (or inserted) object
rather than resorting the whole list
each time an object inside changes.
Why would you update using an index when such updates invalidate the index? Really, I would think that updating by object reference would be more convenient. You can do this with the SortedList - just remember that your Key type is the same as the return type of the function that extracts the comparable data form the object.
class UpdateableSortedList<K,V> {
private SortedList<K,V> list = new SortedList<K,V>();
public delegate K ExtractKeyFunc(V v);
private ExtractKeyFunc func;
public UpdateableSortedList(ExtractKeyFunc f) { func = f; }
public void Add(V v) {
list[func(v)] = v;
}
public void Update(V v) {
int i = list.IndexOfValue(v);
if (i >= 0) {
list.RemoveAt(i);
}
list[func(v)] = v;
}
public IEnumerable<T> Values { get { return list.Values; } }
}
Something like that I guess.