How can I use linq to initialize an array of repeated elements? - c#

At present, I'm using something like this to build a list of 10 objects:
myList = (from _ in Enumerable.Range(0, 10) select new MyObject {...}).toList()
This is based off my python background, where I'd write:
myList = [MyObject(...) for _ in range(10)]
Note that I want my list to contain 10 instances of my object, not the same instance 10 times.
Is this still a sensible way to do things in C#? Is there a cost to doing it this way over a simple for loop?

Fluent API looks a little more readable in this case, but its not very easy to see the intent of your code:
var list = Enumerable.Range(0, 10).Select(_ => new MyObject()).ToList();
Simple if loop is fast and easy to understand, but it also hides intent - creating list of 10 items
List<MyObject> list = new List<MyObject>();
for (int i = 0; i < 10; i++)
list.Add(new MyObject());
The best thing for readability is a builder, which will describe your intent
public class Builder<T>
where T : new()
{
public static IList<T> CreateListOfSize(int size)
{
List<T> list = new List<T>();
for (int i = 0; i < size; i++)
list.Add(new T());
return list;
}
}
Usage:
var list = Builder<MyObject>.CreateListOfSize(10);
This solution is as fast, as simple loop, and intent is very clear. Also in this case we have minimum amount of code to write.

You can try:
Enumerable.Range(0, 1000).Select(x => new MyObject()).ToArray();

Personally, I think Enumerable.Repeat is missing an overload. A handy addition would be something like this:
public static class EnumerableEx
{
public static IEnumerable<T> Repeat<T>(int amt, Func<T> producer)
{
for(var i = 0; i < amt; ++i)
{
yield return producer();
}
}
}
so you could
EnumerableEx.Repeat(10, () => new object()) //.ToList()

Related

How to initialize a 'NotNull' Array of a class in c# without loop?

I want to have something like:
class Main{
SomeClass[] classArray = new SomeClass[199]; // Problem --> All elements are null
for(int i=0; i<classArray.Length; i++){
classArray[i] = new SomeClass();
}
}
class SomeClass{
int x = 1;
public SomeClass(){}
}
but without loop and without doing something like:
SomeClass[] classArray = new SomeClass[] {new SomeClass(), new SomeClass(), ...}
Is this possible?
Enumerable.Range method will generate collection of integers in the given range.
Select method will create new instance for every number.
ToArray will enumerate generated collection and create an array
var yourArray = Enumerable.Range(1, 199).Select(i => new SomeClass()).ToArray();
That's not really possible. You can do several things that result in loops, but don't quite look like loops. For example:
var list = Enumerable.Range(0, 199)
.Select(_ => new SomeClass())
.ToList();

Creating a list filled with new instances of an object

What's the best way to create a list with an arbitrary number of instances of the same object? i.e is there a more compact or efficient way to do the following?
static List<MyObj> MyObjs = Enumerable.Range(0, 100)
.Select(i => new MyObj())
.ToList();
(Enumerable.Repeat would give me ten references to the same object, so I don't think it would work.)
Edited to reflect that this method does not work.
I was curious about your comment about Enumerable.Repeat, so I tried it.
//do not use!
List<object> myList = Enumerable.Repeat(new object(), 100).ToList();
I confirmed that they do all share the same reference like the OP mentioned.
This wouldn't be hard to implement as an iterator:
IEnumerable<T> CreateItems<T> (int count) where T : new() {
return CreateItems(count, () => new T());
}
IEnumerable<T> CreateItems<T> (int count, Func<T> creator) {
for (int i = 0; i < count; i++) {
yield return creator();
}
}
Apparently, the answer is "no". Thanks, everyone!
Not sure what is wrong with a for loop in this case. At the very least, we can presize the capacity of the list. That might not be important for 100 objects, but the size is arbitrary.
public class MyClass
{
static int Capacity = 100;
static List<MyObj> MyObjs = new List<MyObj>(Capacity);
static MyClass() {
for( var i = 0; i < Capacity; i++ ) {
MyObjs.Add(new MyObj());
}
}
}
you can use the enumerable as a base and use select to create the new objects:
List<object> myList = Enumerable.Repeat(null, 100).Select(_ => new object()).ToList();
you can attach a debugger, the new is executed every time.
This is almost the same as your code, but you don't have to provide a fake range.
You only provide a null as fake object you want to repeat...

Regarding Sorting MultiDimensional Arrays in C#

I am trying to figure out a way to correctly sort a bunch of different arraylists.
I am publishing content articles and every value [0] in an arraylist will relate to every other value [0]. and so on. Each element makes up the collective parts of a complete content item.
Now, the last element, popularity, is the amount of clicks an item has received. How do I
do a sort of the content items based on popularity without mixing up the html for each article?
*EDIT I am limited by the .NET 2.0 Framework at Work*
Below is the code... thanks.
public class MultiDimDictList : Dictionary<string, ArrayList> { }
myDicList.Add("fly", a_fly);
myDicList.Add("img", a_img);
myDicList.Add("bar", a_bar);
myDicList.Add("meter", a_meter);
myDicList.Add("block", a_block);
myDicList.Add("popularity", a_pop);
If you use the following code you can convert your existing dictionary of arraylists into a collection of Dictionaries and thus allowing a simple sort using Linq OrderBy
// Get the shortest arraylist length (they should be equal this is just a paranoia check!)
var count=myDicList.Values.Min(x=>x.Count);
// Get the collection of Keys
var keys=myDicList.Keys;
// Perform the conversion
var result=Enumerable.Range(0,count).Select(i=>keys.Select(k=>new {Key=k,Value=myDicList[k][i]}).ToDictionary(x=>x.Key,x=>x.Value));
var sorted=result.OrderByDescending(x=>x["popularity"]).ToList()
-- EDIT VERSION FOR .NET 2.0
First you need a comparer class
class PopularityComparison : IComparer<Dictionary<string,object>> {
private bool _sortAscending;
public PopularityComparison(bool sortAscending) {
_sortAscending = sortAscending;
}
public int Compare(Dictionary<string, object> x, Dictionary<string, object> y) {
object xValue = x["popularity"];
object yValue = y["popularity"];
// Sort Ascending
if (_sortAscending) {
return Comparer.Default.Compare(xValue, yValue);
} else {
return Comparer.Default.Compare(yValue, xValue);
}
}
}
Then you can use the following code
// Get the shortest arraylist length (they should be equal this is just a paranoia check!)
// Replacement for min
int count = int.MaxValue;
foreach (ArrayList a in myDicList.Values) if (a.Count < count) count = a.Count;
// Get the collection of Keys
Dictionary<string, ArrayList>.KeyCollection keys = myDicList.Keys;
// Perform the conversion
List<Dictionary<string, object>> result = new List<Dictionary<string, object>>(count);
for (int i = 0; i < count; i++) {
Dictionary<string, object> row = new Dictionary<string, object>(keys.Count);
foreach (string key in keys) row.Add(key, myDicList[key][i]);
result.Add(row);
}
And then finally to sort in ascending popularity order
result.Sort(new PopularityComparison(true));
or Descending order
result.Sort(new PopularityComparison(true));
I'd think it would be better to have an object containing your keys as properties, then a single collection with each item you'd have in your array lists.
This way you'd have a single collection sort, which becomes trivial if using Linq.OrderBy().
something like...
public class Article
{
public string Fly{get;set;}
public string Img{get;set;}
// etc.
public float Popularity{get;set;}
}
Then...
List<Article> articles = ... get from somewhere, or convert from your array lists.
List<Article> sorted = articles.OrderBy(a=>a.Popularity).ToList();
Please excuse the napkin code here... I'll update it if you need more detail.
An example using non-linq.
Create an implementation of IComparer.
public class ArticleComparer : IComparer<Article>
{
public bool Accending { get; set; }
public int Compare(Article x, Article y)
{
float result = x.Popularity - y.Popularity;
if (!Accending) { result *= -1; }
if (result == 0) { return 0; }
if (result > 0) return 1;
return -1;
}
}
Then when you go to sort the List, you can do something like the following.
ArticleComparer comparer = new ArticleComparer();
comparer.Accending = false;
articles.Sort(comparer);
This would be much easier if you had a list of article objects, each of which contained properties for fly, img, bar, popularity, etc. But if you really have to store things using this inside-out approach, then the only way you can sort the content items based on popularity is to create another array (or list) to hold the order.
Create a new list and populate it with sequential indexes:
List<int> OrderedByPopularity = new List<int>();
ArrayList popList = myDicList["popularity"];
for (int i = 0; i < popList.Count; ++i)
{
OrderedByPopularity.Add(i);
}
Now you have a list that contains the indexes of the items in the popularity list. Now you can sort:
OrderedByPopularity.Sort((i1, i2) => return popList[i1].CompareTo(popList[i2]););
But that gives you the least popular article first. If you want to reverse the sort so that OrderedByPopularity[0] is the most popular item:
OrderedByPopularity.Sort((i1, i2) => { return popList[i2].CompareTo(popList[i1]);});
Really, though, you should look into restructuring your application. It's much easier to work with objects that have properties rather than trying to maintain parallel arrays of properties.
If you have to do this in .NET 2.0, declare the poplist array at class scope (rather than method scope), and create a comparison method.
ArrayList poplist;
void MyMethod()
{
List<int> OrderedByPopularity = new List<int>();
popList = myDicList["popularity"];
for (int i = 0; i < popList.Count; ++i)
{
OrderedByPopularity.Add(i);
}
OrderedByPopularity.Sort(PopularityComparison);
// ...
}
int PopularityComparison(int i1, int i2)
{
return ((int)popList[i2]).CompareTo((int)popList[i1]);
}

C# merge distinct items of 2 collections

I'm looking for a performant way to add distinct items of a second ICollection to an existing one. I'm using .NET 4.
This should do it:
list1.Union(list2).Distinct(aCustomComparer).ToList()
As long as they're IEnumerable, you can use the go-to Linq answer:
var union = firstCollection.Union(secondCollection);
This will use the default equality comparison, which for most objects is referential equality. To change this, you can define an IEqualityComparer generic to the item type in your collection that will perform a more semantic comparison, and specify it as the second argument of the Union.
Another way to add to your exisiting list would be:
list1.AddRange(list2.Distinct().Except(list1));
The most direct answer to your question - since you didn't give much detail on the actual types of ICollection you have as input or need as output is the one given by KeithS
var union = firstCollection.Union(secondCollection);
This will return a distinct IEnumerable - if that is what you need then it is VERY fast. I made a small test app (below) that ran the union method (MethodA) against a simple hashset method of deduplicating and returns a Hashset<>(MethodB). The union method DESTROYS the hashset:
MethodA: 1ms
MethodB: 2827ms
However -- Having to convert that IEnumerable to some other type of collection such as List<> (like the version ADas posted) changes everything:
Simply adding .ToList() to MethodA
var union = firstCollection.Union(secondCollection).ToList();
Changes the results:
MethodA: 3656ms
MethodB: 2803ms
So - it seems more would need to be known about the specific case you are working with - and any solution you come up with should be tested - since a small (code) change can have HUGE impacts.
Below is the test I used to compare these methods - I'm sure it is a stupid way to test - but it seems to work :)
private static void Main(string[] args)
{
ICollection<string> collectionA = new List<string>();
ICollection<string> collectionB = new List<string>();
for (int i = 0; i < 1000; i++)
{
string randomString = Path.GetRandomFileName();
collectionA.Add(randomString);
collectionA.Add(randomString);
collectionB.Add(randomString);
collectionB.Add(randomString);
}
Stopwatch testA = new Stopwatch();
testA.Start();
MethodA(collectionA, collectionB);
testA.Stop();
Stopwatch testB = new Stopwatch();
testB.Start();
MethodB(collectionA, collectionB);
testB.Stop();
Console.WriteLine("MethodA: {0}ms", testA.ElapsedMilliseconds);
Console.WriteLine("MethodB: {0}ms", testB.ElapsedMilliseconds);
Console.ReadLine();
}
private static void MethodA(ICollection<string> collectionA, ICollection<string> collectionB)
{
for (int i = 0; i < 10000; i++)
{
var result = collectionA.Union(collectionB);
}
}
private static void MethodB(ICollection<string> collectionA, ICollection<string> collectionB)
{
for (int i = 0; i < 10000; i++)
{
var result = new HashSet<string>(collectionA);
foreach (string s in collectionB)
{
result.Add(s);
}
}
}

What is the best way to modify a list in a 'foreach' loop?

A new feature in C# / .NET 4.0 is that you can change your enumerable in a foreach without getting the exception. See Paul Jackson's blog entry An Interesting Side-Effect of Concurrency: Removing Items from a Collection While Enumerating for information on this change.
What is the best way to do the following?
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable)
{
item.Add(new item2)
}
}
Usually I use an IList as a cache/buffer until the end of the foreach, but is there better way?
The collection used in foreach is immutable. This is very much by design.
As it says on MSDN:
The foreach statement is used to
iterate through the collection to get
the information that you want, but can
not be used to add or remove items
from the source collection to avoid
unpredictable side effects. If you
need to add or remove items from the
source collection, use a for loop.
The post in the link provided by Poko indicates that this is allowed in the new concurrent collections.
Make a copy of the enumeration, using an IEnumerable extension method in this case, and enumerate over it. This would add a copy of every element in every inner enumerable to that enumeration.
foreach(var item in Enumerable)
{
foreach(var item2 in item.Enumerable.ToList())
{
item.Add(item2)
}
}
To illustrate Nippysaurus's answer: If you are going to add the new items to the list and want to process the newly added items too during the same enumeration then you can just use for loop instead of foreach loop, problem solved :)
var list = new List<YourData>();
... populate the list ...
//foreach (var entryToProcess in list)
for (int i = 0; i < list.Count; i++)
{
var entryToProcess = list[i];
var resultOfProcessing = DoStuffToEntry(entryToProcess);
if (... condition ...)
list.Add(new YourData(...));
}
For runnable example:
void Main()
{
var list = new List<int>();
for (int i = 0; i < 10; i++)
list.Add(i);
//foreach (var entry in list)
for (int i = 0; i < list.Count; i++)
{
var entry = list[i];
if (entry % 2 == 0)
list.Add(entry + 1);
Console.Write(entry + ", ");
}
Console.Write(list);
}
Output of last example:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 3, 5, 7, 9,
List (15 items)
0
1
2
3
4
5
6
7
8
9
1
3
5
7
9
As mentioned, but with a code sample:
foreach(var item in collection.ToArray())
collection.Add(new Item...);
You should really use for() instead of foreach() in this case.
You can't change the enumerable collection while it is being enumerated, so you will have to make your changes before or after enumerating.
The for loop is a nice alternative, but if your IEnumerable collection does not implement ICollection, it is not possible.
Either:
1) Copy collection first. Enumerate the copied collection and change the original collection during the enumeration. (#tvanfosson)
or
2) Keep a list of changes and commit them after the enumeration.
LINQ is very effective for juggling with collections.
Your types and structure are unclear to me, but I will try to fit your example to the best of my ability.
From your code it appears that, for each item, you are adding to that item everything from its own 'Enumerable' property. This is very simple:
foreach (var item in Enumerable)
{
item = item.AddRange(item.Enumerable));
}
As a more general example, let's say we want to iterate a collection and remove items where a certain condition is true. Avoiding foreach, using LINQ:
myCollection = myCollection.Where(item => item.ShouldBeKept);
Add an item based on each existing item? No problem:
myCollection = myCollection.Concat(myCollection.Select(item => new Item(item.SomeProp)));
Here's how you can do that (quick and dirty solution. If you really need this kind of behavior, you should either reconsider your design or override all IList<T> members and aggregate the source list):
using System;
using System.Collections.Generic;
namespace ConsoleApplication3
{
public class ModifiableList<T> : List<T>
{
private readonly IList<T> pendingAdditions = new List<T>();
private int activeEnumerators = 0;
public ModifiableList(IEnumerable<T> collection) : base(collection)
{
}
public ModifiableList()
{
}
public new void Add(T t)
{
if(activeEnumerators == 0)
base.Add(t);
else
pendingAdditions.Add(t);
}
public new IEnumerator<T> GetEnumerator()
{
++activeEnumerators;
foreach(T t in ((IList<T>)this))
yield return t;
--activeEnumerators;
AddRange(pendingAdditions);
pendingAdditions.Clear();
}
}
class Program
{
static void Main(string[] args)
{
ModifiableList<int> ints = new ModifiableList<int>(new int[] { 2, 4, 6, 8 });
foreach(int i in ints)
ints.Add(i * 2);
foreach(int i in ints)
Console.WriteLine(i * 2);
}
}
}
To add to Timo's answer LINQ can be used like this as well:
items = items.Select(i => {
...
//perform some logic adding / updating.
return i / return new Item();
...
//To remove an item simply have logic to return null.
//Then attach the Where to filter out nulls
return null;
...
}).Where(i => i != null);
The best approach from a performance perspective is probably to use a one or two arrays. Copy the list to an array, do operations on the array, and then build a new list from the array. Accessing an array element is faster than accessing a list item, and conversions between a List<T> and a T[] can use a fast "bulk copy" operation which avoids the overhead associated accessing individual items.
For example, suppose you have a List<string> and wish to have every string in the list which starts with T be followed by an item "Boo", while every string that starts with "U" is dropped entirely. An optimal approach would probably be something like:
int srcPtr,destPtr;
string[] arr;
srcPtr = theList.Count;
arr = new string[srcPtr*2];
theList.CopyTo(arr, theList.Count); // Copy into second half of the array
destPtr = 0;
for (; srcPtr < arr.Length; srcPtr++)
{
string st = arr[srcPtr];
char ch = (st ?? "!")[0]; // Get first character of string, or "!" if empty
if (ch != 'U')
arr[destPtr++] = st;
if (ch == 'T')
arr[destPtr++] = "Boo";
}
if (destPtr > arr.Length/2) // More than half of dest. array is used
{
theList = new List<String>(arr); // Adds extra elements
if (destPtr != arr.Length)
theList.RemoveRange(destPtr, arr.Length-destPtr); // Chop to proper length
}
else
{
Array.Resize(ref arr, destPtr);
theList = new List<String>(arr); // Adds extra elements
}
It would have been helpful if List<T> provided a method to construct a list from a portion of an array, but I'm unaware of any efficient method for doing so. Still, operations on arrays are pretty fast. Of note is the fact that adding and removing items from the list does not require "pushing" around other items; each item gets written directly to its appropriate spot in the array.
I have written one easy step, but because of this performance will be degraded
Here is my code snippet:-
for (int tempReg = 0; tempReg < reg.Matches(lines).Count; tempReg++)
{
foreach (Match match in reg.Matches(lines))
{
var aStringBuilder = new StringBuilder(lines);
aStringBuilder.Insert(startIndex, match.ToString().Replace(",", " ");
lines[k] = aStringBuilder.ToString();
tempReg = 0;
break;
}
}

Categories

Resources