Iteration over collection VS using enumerator - c#

var range = Enumerable.Range(0, 1000);
foreach (var i in new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 })
{
foreach (var r in range)
{
var d = range.Contains(i);
}
}
Given that 'range' variable content is available from memory what would be the best choice?
To keep iterator var range = Enumerable.Range(0, 1000); and have it work over 10 times
To convert into a collection var range = Enumerable.Range(0, 1000).ToArray(); and call Contains on an already created collection

Related

Take n elements. If at end start from begining

How can I take n elements from a m elements collection so that if I run out of elements it starts from the beginning?
List<int> list = new List<int>() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<int> newList = list.Skip(9).Take(2).ToList();
List<int> expected = new List(){10,1};
CollectionAssert.AreEqual(expected, newList);
How can I get the expected list?
I'm looking for a CircularTake() function or something in that direction.
use an extension method to circular repeat the enumerable
public static IEnumerable<T> Circular<T>( this IEnumerable<T> source )
{
while (true)
foreach (var item in source)
yield return item;
}
and you can use your code
List<int> list = new List<int>() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<int> newList = list.Circular().Skip(9).Take(2).ToList();
.net fiddle example
You don't need to track the overflow because we can use the % modulus operator (which returns the remainder from an integer division) to continually loop through a range of indexes, and it will always return a valid index in the collection, wrapping back to 0 when it gets to the end (and this will work for multiple wraps around the end of the list):
List<int> list = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<int> newList = new List<int>();
for (int skip = 9, take = 2; take > 0; skip++, take--)
{
newList.Add(list[skip % list.Count]);
}
Result:
// newList == { 10, 1 }
This could be extracted into an extension method:
public static List<T> SkipTakeWrap<T>(this List<T> source, int skip, int take)
{
var newList = new List<T>();
while (take > 0)
{
newList.Add(source[skip % source.Count]);
skip++;
take--;
}
return newList;
}
And then it could be called like:
List<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> newList = list.SkipTakeWrap(9, 2);
you may need to do something like this
var start = 9;
var amount = 2;
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> listOverflow = list.ToList();
var overflow = (start + amount) - list.Count;
if (overflow > 0)
for (var i = 0; i < overflow; i++)
listOverflow.AddRange(list.ToList());
var newList = listOverflow.Skip(start).Take(amount).ToList();
My take on a CircularTake extension.
public static IEnumerable<T> CircularTake<T>(this IReadOnlyList<T> source, int count)
{
return Enumerable.Range(0, count).Select(i => source[i % source.Count]);
}
int overflow = take - (elements.Count - skip);
if(overflow > 0)
{
results.AddRange(elements.Skip(skip).Take(take - overflow));
results.AddRange(elements.Take(overflow));
}
If there is a possiblity that there are more than one circular iterations, e.g. from 3 elements, take 10 or more, then you can apply this logic in a recursive function.

Lambda where id does not exist in another list

I have to exclude items whose ids exist in another list.
List<Int64> Listofid;
var filteredlist = curProjArea.Project.ForEach(x => {x.ProjectId = (where
project id does not exist in Listofid) });
Is this possible?
You can filter projects in Where clause:
List<Int64> Listofid;
var filteredlist = curProjArea.Project.Where(x => !Listofid.Contains(x.ProjectId));
List<Int64> Listofid;
var filteredlist = curProjArea.Project.Where(x => !Listofid.Contains(x.ProjectId)).ToList();
Try this out once
int[] values1 = { 1, 2, 3, 4 };
// Contains three values (1 and 2 also found in values1).
int[] values2 = { 1, 2, 5 };
// Remove all values2 from values1.
var result = values1.Except(values2);
// Show.
foreach (var element in result)
{
Console.WriteLine(element);
}
From:
https://www.dotnetperls.com/except
I think , It's useful for you
List<Int64> Listofid = new List<Int64>() { 5, 3, 9, 7, 5, 9, 3, 7 };
List<Int64> filteredlist = new List<Int64>() { 8, 3, 6, 4, 4, 9, 1, 0 };
List<Int64> Except = filteredlist.Except(Listofid).ToList();
Console.WriteLine("Except Result");
foreach (int num in Except)
{
Console.WriteLine("{0} ", num); //Result = 8,6,4,1,0
}
Just negate the .Contains on the list for which you want to exclude it.
var filteredList = curProjArea.Project.Where(a => !Listofid.Contains(a.ProjectId));
Demo in Dotnet fiddle

The union of the intersects of the 2 set combinations of a sequence of sequences

How can I find the set of items that occur in 2 or more sequences in a sequence of sequences?
In other words, I want the distinct values that occur in at least 2 of the passed in sequences.
Note:
This is not the intersect of all sequences but rather, the union of the intersect of all pairs of sequences.
Note 2:
The does not include the pair, or 2 combination, of a sequence with itself. That would be silly.
I have made an attempt myself,
public static IEnumerable<T> UnionOfIntersects<T>(
this IEnumerable<IEnumerable<T>> source)
{
var pairs =
from s1 in source
from s2 in source
select new { s1 , s2 };
var intersects = pairs
.Where(p => p.s1 != p.s2)
.Select(p => p.s1.Intersect(p.s2));
return intersects.SelectMany(i => i).Distinct();
}
but I'm concerned that this might be sub-optimal, I think it includes intersects of pair A, B and pair B, A which seems inefficient. I also think there might be a more efficient way to compound the sets as they are iterated.
I include some example input and output below:
{ { 1, 1, 2, 3, 4, 5, 7 }, { 5, 6, 7 }, { 2, 6, 7, 9 } , { 4 } }
returns
{ 2, 4, 5, 6, 7 }
and
{ { 1, 2, 3} } or { {} } or { }
returns
{ }
I'm looking for the best combination of readability and potential performance.
EDIT
I've performed some initial testing of the current answers, my code is here. Output below.
Original valid:True
DoomerOneLine valid:True
DoomerSqlLike valid:True
Svinja valid:True
Adricadar valid:True
Schmelter valid:True
Original 100000 iterations in 82ms
DoomerOneLine 100000 iterations in 58ms
DoomerSqlLike 100000 iterations in 82ms
Svinja 100000 iterations in 1039ms
Adricadar 100000 iterations in 879ms
Schmelter 100000 iterations in 9ms
At the moment, it looks as if Tim Schmelter's answer performs better by at least an order of magnitude.
// init sequences
var sequences = new int[][]
{
new int[] { 1, 2, 3, 4, 5, 7 },
new int[] { 5, 6, 7 },
new int[] { 2, 6, 7, 9 },
new int[] { 4 }
};
One-line way:
var result = sequences
.SelectMany(e => e.Distinct())
.GroupBy(e => e)
.Where(e => e.Count() > 1)
.Select(e => e.Key);
// result is { 2 4 5 7 6 }
Sql-like way (with ordering):
var result = (
from e in sequences.SelectMany(e => e.Distinct())
group e by e into g
where g.Count() > 1
orderby g.Key
select g.Key);
// result is { 2 4 5 6 7 }
May be fastest code (but not readable), complexity O(N):
var dic = new Dictionary<int, int>();
var subHash = new HashSet<int>();
int length = array.Length;
for (int i = 0; i < length; i++)
{
subHash.Clear();
int subLength = array[i].Length;
for (int j = 0; j < subLength; j++)
{
int n = array[i][j];
if (!subHash.Contains(n))
{
int counter;
if (dic.TryGetValue(n, out counter))
{
// duplicate
dic[n] = counter + 1;
}
else
{
// first occurance
dic[n] = 1;
}
}
else
{
// exclude duplucate in sub array
subHash.Add(n);
}
}
}
This should be very close to optimal - how "readable" it is depends on your taste. In my opinion it is also the most readable solution.
var seenElements = new HashSet<T>();
var repeatedElements = new HashSet<T>();
foreach (var list in source)
{
foreach (var element in list.Distinct())
{
if (seenElements.Contains(element))
{
repeatedElements.Add(element);
}
else
{
seenElements.Add(element);
}
}
}
return repeatedElements;
You can skip already Intesected sequences, this way will be a little faster.
public static IEnumerable<T> UnionOfIntersects<T>(this IEnumerable<IEnumerable<T>> source)
{
var result = new List<T>();
var sequences = source.ToList();
for (int sequenceIdx = 0; sequenceIdx < sequences.Count(); sequenceIdx++)
{
var sequence = sequences[sequenceIdx];
for (int targetSequenceIdx = sequenceIdx + 1; targetSequenceIdx < sequences.Count; targetSequenceIdx++)
{
var targetSequence = sequences[targetSequenceIdx];
var intersections = sequence.Intersect(targetSequence);
result.AddRange(intersections);
}
}
return result.Distinct();
}
How it works?
Input: {/*0*/ { 1, 2, 3, 4, 5, 7 } ,/*1*/ { 5, 6, 7 },/*2*/ { 2, 6, 7, 9 } , /*3*/{ 4 } }
Step 0: Intersect 0 with 1..3
Step 1: Intersect 1 with 2..3 (0 with 1 already has been intersected)
Step 2: Intersect 2 with 3 (0 with 2 and 1 with 2 already has been intersected)
Return: Distinct elements.
Result: { 2, 4, 5, 6, 7 }
You can test it with the below code
var lists = new List<List<int>>
{
new List<int> {1, 2, 3, 4, 5, 7},
new List<int> {5, 6, 7},
new List<int> {2, 6, 7, 9},
new List<int> {4 }
};
var result = lists.UnionOfIntersects();
You can try this approach, it might be more efficient and also allows to specify the minimum intersection-count and the comparer used:
public static IEnumerable<T> UnionOfIntersects<T>(this IEnumerable<IEnumerable<T>> source
, int minIntersectionCount
, IEqualityComparer<T> comparer = null)
{
if (comparer == null) comparer = EqualityComparer<T>.Default;
foreach (T item in source.SelectMany(s => s).Distinct(comparer))
{
int containedInHowManySequences = 0;
foreach (IEnumerable<T> seq in source)
{
bool contained = seq.Contains(item, comparer);
if (contained) containedInHowManySequences++;
if (containedInHowManySequences == minIntersectionCount)
{
yield return item;
break;
}
}
}
}
Some explaining words:
It enumerates all unique items in all sequences. Since Distinct is using a set this should be pretty efficient. That can help to speed up in case of many duplicates in all sequences.
The inner loop just looks into every sequence if the unique item is contained. Thefore it uses Enumerable.Contains which stops execution as soon as one item was found(so duplicates are no issue).
If the intersection-count reaches the minum intersection count this item is yielded and the next (unique) item is checked.
That should nail it:
int[][] test = { new int[] { 1, 2, 3, 4, 5, 7 }, new int[] { 5, 6, 7 }, new int[] { 2, 6, 7, 9 }, new int[] { 4 } };
var result = test.SelectMany(a => a.Distinct()).GroupBy(x => x).Where(g => g.Count() > 1).Select(y => y.Key).ToList();
First you make sure, there are no duplicates in each sequence. Then you join all sequences to a single sequence and look for duplicates as e.g. here.

How to display how many times an array element appears

I am new to C# and hope I can get some help on this topic. I have an array with elements and I need to display how many times every item appears.
For instance, in [1, 2, 3, 4, 4, 4, 3], 1 appears one time, 4 appears three times, and so on.
I have done the following but don`t know how to put it in the foreach/if statement...
int[] List = new int[]{1,2,3,4,5,4,4,3};
foreach(int d in List)
{
if("here I want to check for the elements")
}
Thanks you, and sorry if this is a very basic one...
You can handle this via Enumerable.GroupBy. I recommend looking at the C# LINQ samples section on Count and GroupBy for guidance.
In your case, this can be:
int[] values = new []{1,2,3,4,5,4,4,3};
var groups = values.GroupBy(v => v);
foreach(var group in groups)
Console.WriteLine("Value {0} has {1} items", group.Key, group.Count());
You can keep a Dictionary of items found as well as their associated counts. In the example below, dict[d] refers to an element by its value. For example d = 4.
int[] List = new int[]{1,2,3,4,5,4,4,3};
var dict = new Dictionary<int, int>();
foreach(int d in List)
{
if (dict.ContainsKey(d))
dict[d]++;
else
dict.Add(d, 1);
}
When the foreach loop terminates you'll have one entry per unique value in dict. You can get the count of each item by accessing dict[d], where d is some integer value from your original list.
The LINQ answers are nice, but if you're trying to do it yourself:
int[] numberFound = new int[6];
int[] List = new int[] { 1, 2, 3, 4, 5, 4, 4, 3 };
foreach (int d in List)
{
numberFound[d]++;
}
var list = new int[] { 1, 2, 3, 4, 5, 4, 4, 3 };
var groups = list.GroupBy(i => i).Select(i => new { Number = i.Key, Count = i.Count() });
private static void CalculateNumberOfOccurenceSingleLoop()
{
int[] intergernumberArrays = { 1, 2, 3, 4, 1, 2, 4, 1, 2, 3, 5, 6, 1, 2, 1, 1, 2 };
Dictionary<int, int> NumberOccurence = new Dictionary<int, int>();
for (int i = 0; i < intergernumberArrays.Length; i++)
{
if (NumberOccurence.ContainsKey(intergernumberArrays[i]))
{
var KeyValue = NumberOccurence.Where(j => j.Key == intergernumberArrays[i]).FirstOrDefault().Value;
NumberOccurence[intergernumberArrays[i]] = KeyValue + 1;
}
else
{
NumberOccurence.Add(intergernumberArrays[i], 1);
}
}
foreach (KeyValuePair<int, int> item in NumberOccurence)
{
Console.WriteLine(item.Key + " " + item.Value);
}
Console.ReadLine();
}

How to iterate through Dictionary<MyEnum, List<int>> and each time return part of values of each list?

Each key in dictionary has list of MANY integers. I need to iterate through each key and each time to take n items from list and do it until I iterate through all items in all lists. What is the best way to implement it? Do I need to implement some Enumerator?
The code:
enum ItemType { Type1=1, Type2=2, Type3=3 };
var items = new Dictionary<ItemType, List<int>>();
items[ItemType.Type1] = new List<int> { 1, 2, 3, 4, 5 };
items[ItemType.Type2] = new List<int> { 11, 12, 13, 15 };
items[ItemType.Type3] = new List<int> { 21, 22, 23, 24, 25, 26 };
For example: n=2.
1st iteration returns 1,2,11,12,21,22
2nd iteration returns 3,4,13,15,23,24
3rd iteration returns 5,25,26
UPDATED:
at the end I have to get list of this items in that order : 1,2,11,12,21,22, 3,4,13,15,23,24, 5,25,26
Here is how it might be done:
enum ItemType { Type1 = 1, Type2 = 2, Type3 = 3 };
Dictionary<ItemType, List<int>> items = new Dictionary<ItemType, List<int>>();
items[ItemType.Type1] = new List<int> { 1, 2, 3, 4, 5 };
items[ItemType.Type2] = new List<int> { 11, 12, 13, 15 };
items[ItemType.Type3] = new List<int> { 21, 22, 23, 24, 25, 26 };
// Define upper boundary of iteration
int max = items.Values.Select(v => v.Count).Max();
int i = 0, n = 2;
while (i + n <= max)
{
// Skip and Take - to select only next portion of elements, SelectMany - to merge resulting lists of portions
List<int> res = items.Values.Select(v => v.Skip(i).Take(n)).SelectMany(v => v).ToList();
i += n;
// Further processing of res
}
You don't need to define your custom enumerator, just use the MoveNext manually:
Step 1, convert you Dictionary<ItemType, List<int>> into Dictionary<ItemType, List<IEnumerator<int>>:
var iterators = items.ToDictionary(p => p.Key, p => (IEnumerator<int>)p.Value.GetEnumerator());
Step 2: handle MoveNext manually:
public List<int> Get(Dictionary<ItemType, IEnumerator<int>> iterators, int n)
{
var result = new List<int>();
foreach (var itor in iterators.Values)
{
for (var i = 0; i < n && itor.MoveNext(); i++)
{
result.Add(itor.Current);
}
}
return result;
}
Calling Get multiple times will give you the expected result. The enumerator itself will keep the current position.
This will do it for you:
var resultList = new List<int>();
items.ToList().ForEach(listInts => resultList.AddRange(listInts.Take(n));
This is letting LINQ extensions do the hard work for you. Take() will take as much as it can without throwing an exception if you request more than what there is. In this case I'm adding the results to another list, but you could just as easily tag another ForEach() on the end of the Take() in order to iterate the results.
I notice from the example sequences that you are retriving n number of items from x starting point - if you edit your question to include how the starting point is decided then I will adjust my example.
Edit:
Because you want to take n number of items from each list each iteration until there are no more elements returned, this will do it:
class Program
{
static void Main(string[] args)
{
var items = new Dictionary<ItemType, List<int>>();
items[ItemType.Type1] = new List<int> { 1, 2, 3, 4, 5 };
items[ItemType.Type2] = new List<int> { 11, 12, 13, 15 };
items[ItemType.Type3] = new List<int> { 21, 22, 23, 24, 25, 26 };
int numItemsTaken = 0;
var resultsList = new List<int>();
int n = 2, startpoint = 0, previousListSize = 0;
do
{
items.ToList().ForEach(x => resultsList.AddRange(x.Value.Skip(startpoint).Take(n)));
startpoint += n;
numItemsTaken = resultsList.Count - previousListSize;
previousListSize = resultsList.Count;
}
while (numItemsTaken > 0);
Console.WriteLine(string.Join(", ", resultsList));
Console.ReadKey();
}
enum ItemType { Type1 = 1, Type2 = 2, Type3 = 3 };
}
This is one of the few times you'll use a do while loop, and it will work regardless of the size of n or the size of your lists or how many lists there are.
The "best way" depends on your goal, e.g. readability or performance.
Here's one way:
var firstIter = items.Values.SelectMany(list => list.Take(2));
var secondIter = items.Values.SelectMany(list => list.Skip(2).Take(2));
var thirdIter = items.Values.SelectMany(list => list.Skip(4).Take(2));
var finalResult = firstIter.Concat(secondIter).Concat(thirdIter);
Edit: Here's a more general version:
var finalResult = Flatten(items, 0, 2);
IEnumerable<int> Flatten(
Dictionary<ItemType, List<int>> items,
int skipCount,
int takeCount)
{
var iter = items.Values.SelectMany(list => list.Skip(skipCount).Take(takeCount));
return
iter.Count() == 0 ? // a bit inefficient here
iter :
iter.Concat(Flatten(items, skipCount + takeCount, takeCount));
}

Categories