Create sequence consisting of multiple property values - c#

I have an existing collection of objects with two properties of interest. Both properties are of the same type. I want to create a new sequence consisting of the property values. Here's one way (I'm using tuples instead of my custom type for simplicity):
var list = new List<Tuple<string, string>>
{ Tuple.Create("dog", "cat"), Tuple.Create("fish", "frog") };
var result =
list.SelectMany(x => new[] {x.Item1, x.Item2});
foreach (string item in result)
{
Console.WriteLine(item);
}
Results in:
dog
cat
fish
frog
This gives me the results I want, but is there a better way to accomplish this (in particular, without the need to create arrays or collections)?
Edit:
This also works, at the cost of iterating over the collection twice:
var result = list.Select(x => x.Item1).Concat(list.Select(x => x.Item2));

If you want to avoid creating another collection, you could yield the results instead.
void Main()
{
var list = new List<Tuple<string, string>>
{ Tuple.Create("dog", "cat"), Tuple.Create("fish", "frog") };
foreach (var element in GetSingleList(list))
{
Console.WriteLine (element);
}
}
// A reusable extension method would be a better approach.
IEnumerable<T> GetSingleList<T>(IEnumerable<Tuple<T,T>> list) {
foreach (var element in list)
{
yield return element.Item1;
yield return element.Item2;
}
}

I think your approach is fine and I would stick with that. The use of the array nicely gets the job done when using SelectMany, and the final result is an IEnumerable<string>.
There are some alternate approaches, but I think they're more verbose than your approach.
Aggregate approach:
var result = list.Aggregate(new List<string>(), (seed, t) =>
{
seed.Add(t.Item1);
seed.Add(t.Item2);
return seed;
});
result.ForEach(Console.WriteLine);
ForEach approach:
var result = new List<string>();
list.ForEach(t => { result.Add(t.Item1); result.Add(t.Item2); });
result.ForEach(Console.WriteLine);
In both cases a new List<string> is created.

Related

How to improve foreach within foreach

I have a foreach loop within foreach loop which looks like this:
// Item is an abstract class. Item1, Item2, etc. are his heirs.
List<Item> allItems = new List<Item> { new Item1(), new Item2(), new Item3(), new Item4() };
List<Type> affectedItems = new List<Type> { typeof(Item1), typeof(Item3) };
foreach(Item i in allItems)
foreach(Type t in affectedItems)
if(i.GetType().Equals(t))
{
// does something
}
How can I improve my code so inner loop would not waste so much time checking for nonexistent items in a list?
Any linq extension method you use (eg Where, Any) is an extra loop.
You need to minimize the number of loops (especially the nested ones), in your case the best way is to use a fast lookup data structure:
List<Item> allItems = new List<Item>{ new Item1(), new Item2(), new Item3(), new Item4() };
HashSet<Type> affectedItems = new HashSet<Type>(){ typeof(Item1), typeof(Item3) };
foreach (Item i in allItems)
{
if (affectedItems.Contains(i.GetType()))
{
// Do Something
}
}
This is the fastest approach so far with minimal loops and takes up to 0.02 milliseconds, while other methods take up to 0.7.
A quick advise, whenever you have Loop up process and you want to optimize look for data structures to use like HashSet, Dictionary, Lookup, etc..
Write single loop like this:
foreach (Item i in allItems.Where (item => affectedItems.
Any (type => type.Equals (item.GetType ()))))
This will return only items from allItems that are type from affectedItems.
The only difference from your code is that Any will stop searching after first type is found. That's the only improvement. But you can add break in your if statement. Then these two code snippets would be equivalent.
If you have a large list of types then changing your list to HashSet could help in performance otherwise it doesn't make much difference.
List<Item> allItems = new List<Item> { new Item1(), new Item2(), new Item3(), new Item4() };
HashSet<Type> affectedItems = new HashSet<Type> { typeof(Item1), typeof(Item3) };
var items = allItems.Where(item=> affectedItems.Contains(item.GetType()));
foreach(var item in items)
{
// does something
}
This one was the quickest (I try your code, Linq with intersect and this one):
Array.ForEach(allItems.ToArray(), i => {
var t = i.GetType();
if (affectedItems.Contains(t)) {
// Do Something
}
});

How can I add an item to a list and return a new list

I was asked this question today:
How can I add an item to a list and return that list back?
The code for List<T>.Add(T) returns void. So you can't do something like this:
var list = new List<string>{"item1","item2"};
var newList = list.Add("item3");
This is related to using AutoMapper, although that part isn't particularly important.
One option is Linq, with Concat:
var list = new List<string>{"item1", "item2"};
var newList = list.Concat(new[] { "item3" }).ToList();
In typical Linq fashion, list stays the same, and newList contains all the items from list as well as the items in the new list, in this case just "item3".
You can skip the .ToList() to keep the IEnumerable<string> result if that fits your use case.
If you find yourself doing this often with individual items, you can use something like this extension method to pass them without the new[] { ... } syntax:
public static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> source, params T[] items)
{
return source.Concat(items);
}
Because of the params array the earlier example becomes:
var list = new List<string>{"item1", "item2"};
var newList = list.ConcatItems("item3").ToList();
Make sure not to mix this up with Union, which removes duplicate items. (Searching for those duplicates is overhead that you probably don't want!)
The answer to this question was relatively simple:
var list = new List<string>(new List<string>{"item1","item2"}){"item3"};
List<T>() has a constructor that can take in IEnumerable<T> (MSDN). Additionally, you can use the object setter to put new items into the list.
So, for a more complicated example:
var originalList = new List<string>();
originalList.Add("item1");
originalList.Add("item2");
var newList = new List<string>(originalList){"item3"};
You can simply do :
List<string> list = new List<string>{"item1","item2"};
List<string> newList = null;
(newList = list.ToList()).Add("item3");
Or create your own extension method :
public static class Helper
{
public static List<T> MyAdd<T>(this List<T> collection, T item)
{
collection.Add(item);
return collection;
}
}
And use it :
List<string> list = new List<string>{"item1","item2"};
List<string> newList = list.MyAdd("item3"); // same object though
List<string> newList2 = newList.ToList().MyAdd("item4").MyAdd("item5"); // different object
One property of an ImmutableList<T> (and other similar data structures from System.Collections.Immutable) is that it doesn't mutate the original list, it returns another immutable list with the added value.
So doing this:
var originalImmutable = ImmutableList<int>.Create(1, 2);
var otherImmutable = originalImmutable.Add(3);
Will result in a shallow copied new list each time you call Add.
The most readable and maintainable solution is to copy the list and then add the item:
var list = new List<string>{"item1","item2"};
var newList = list.toList();
newList.Add("item3");
Seven years have passed since the question has been asked but Enumerable class now offers Prepend and Append methods that could be used in a straightforward fashion:
var list = new List<string>{"item1","item2"};
var newList = list.Append("item3").ToList();

What is the best way to trim a list?

I have a List of strings. Its being generated elsewhere but i will generate it below to help describe this simplified example
var list = new List<string>();
list.Add("Joe");
list.Add("");
list.Add("Bill");
list.Add("Bill");
list.Add("");
list.Add("Scott");
list.Add("Joe");
list.Add("");
list.Add("");
list = TrimList(list);
I would like a function that "trims" this list and by trim I want to remove all items at the end of the array that are blank strings (the final two in this case).
NOTE: I still want to keep the blank one that is the second item in the array (or any other one that is just not at the end) so I can't do a .Where(r=> String.isNullOrEmpty(r))
I would just write it without any LINQ, to be honest- after all, you're modifying a collection rather than just querying it:
void TrimList(List<string> list)
{
int lastNonEmpty = list.FindLastIndex(x => !string.IsNullOrEmpty(x));
int firstToRemove = lastNonEmpty + 1;
list.RemoveRange(firstToRemove, list.Count - firstToRemove);
}
If you actually want to create a new list, then the LINQ-based solutions are okay... although potentially somewhat inefficient (as Reverse has to buffer everything).
Take advantage of Reverse and SkipWhile.
list = list.Reverse().SkipWhile(s => String.IsNullOrEmpty(s)).Reverse().ToList();
List<T> (not the interface) has a FindLastIndex method. Therefore you can wrap that in a method:
static IList<string> TrimList(List<string> input) {
return input.Take(input.FindLastIndex(x => !string.IsNullOrEmpty(x)) + 1)
.ToList();
}
This produces a copy, whereas Jon's modifies the list.
The only solution I can think of is to code a loop that starts at the end of the list and searches for an element that is not an empty string. Don't know of any library functions that would help. Once you know the last good element, you know which ones to remove.
Be careful not to modify the collection while you are iterating over it. Tends to break the iterator.
I always like to come up with the most generic solution possible. Why restrict yourself with lists and strings? Let's make an algorithm for generic enumerable!
public static class EnumerableExtensions
{
public static IEnumerable<T> TrimEnd<T>(this IEnumerable<T> enumerable, Predicate<T> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException("predicate");
}
var accumulator = new LinkedList<T>();
foreach (var item in enumerable)
{
if (predicate(item))
{
accumulator.AddLast(item);
}
else
{
foreach (var accumulated in accumulator)
{
yield return accumulated;
}
accumulator.Clear();
yield return item;
}
}
}
}
Use it like this:
var list = new[]
{
"Joe",
"",
"Bill",
"Bill",
"",
"Scott",
"Joe",
"",
""
};
foreach (var item in list.TrimEnd(string.IsNullOrEmpty))
{
Console.WriteLine(item);
}

Scan nested dictionary with LINQ syntax

I have this working code:
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
public class Example {
public static void Main(string[] args) {
var files = new Dictionary<string, Dictionary<string, int>>()
{ { "file1", new Dictionary<string, int>() { { "A", 1 } } } };
foreach(var file in files) {
File.WriteAllLines(file.Key + ".txt", file.Value.Select(
item => item.Key + item.Value.ToString("000")).ToArray());
}
}
}
But I want to change the foreach to LINQ syntax. Nothing I already tried worked.
Is this what you are after?
var files = new Dictionary<string, Dictionary<string, int>>()
{ { "file1", new Dictionary<string, int>() { { "A", 1 } } } };
files.ForEach(kvp =>
File.WriteAllLines(kvp.Key + ".txt", kvp.Value.Select(
item => item.Key + item.Value.ToString("000")).ToArray()));
As per Alexei's comment, IEnumerable.ForEach isn't a standard extension method as it implies mutation, which isn't the aim of functional programming. You can add it with a helper method like this one:
public static void ForEach<T>(
this IEnumerable<T> source,
Action<T> action)
{
foreach (T element in source)
action(element);
}
Also, your original title implied that the initializer syntax for Dictionaries is unwieldy. What you can do to reduce the amount of typing / code real estate for a large number of elements is to build up an array of anonymous objects and then ToDictionary(). Unfortunately there is a small performance impact:
var files = new [] { new { key = "file1",
value = new [] { new {key = "A", value = 1 } } } }
.ToDictionary(
_ => _.key,
_ => _.value.ToDictionary(x => x.key, x => x.value));
foreach is exactly what you should be using here. LINQ is all about querying data: projecting, filtering, sorting, grouping, etc. You're trying to execute an action for each element in collection which is already in there as you it.
Just iterate using foreach.
There are reasons why there is no ForEach extension method on IEnumerable<T>:
Why is there not a ForEach extension method on the IEnumerable interface?
Why I Don’t Use the ForEach Extension Method
It's mostly about:
The reason to not use ForEach is that it blurs the boundary between pure functional code and state-full imperative code.
The only reason I can see not to use foreach loop is when you want to make your actions run in parallel by using Parallel.ForEach instead:
Parallel.ForEach(
files,
kvp => File.WriteAllLines(kvp.Key + ".txt", kvp.Value.Select(
item => item.Key + item.Value.ToString("000")).ToArray()));
Having ForEach extension method on IEnumerable<T> is a bad design and I advice against it.

Using LINQ's Zip with a closure that doesn't return a value

Disclaimer: this question is driven by my personal curiosity more than an actual need to accomplish something. So my example is going to be contrived.
Nevertheless I think it's an issue that might very well crop up.
Let's say we are using Zip to iterate over two sequences, invoking a void method that just throws an exception if one item of the couple is found to be different from the other (therefore discarding any return value). The point here is not that the method throws an exception, so much as it returns void.
In other words, we're kind of doing a ForEach over two collections (and by the way, I know what Eric Lippert thinks about ForEach, and fully agree with him and never use it).
Now, Zip wants a Func<TFirst, TSecond, TResult>, so of course passing something equivalent to Action<TFirst, TSecond> won't work.
My question is: is there an idiomatic way that is better than this (i.e. returning a dummy value)?
var collection1 = new List<int>() { ... };
var collection2 = new List<int>() { ... };
collection1.Zip(collection2, (first, second) =>
{
VoidMethodThatThrows(first, second);
return true;
});
Use Zip() to throw the items into an object, then do your foreach however way you choose (do a normal foreach loop please, not the bad ToList/ForEach combo).
var items = collection1.Zip(collection2, (x, y) => new { First = x, Second = y });
foreach (var item in items)
{
VoidMethodThatThrows(item.First, item.Second);
}
As of C# 7.0, improved tuple support and deconstruction makes it far more pleasing to work with.
var items = collection1.Zip(collection2, (x, y) => (x, y));
// or collection1.Zip(collection2, ValueTuple.Create);
foreach (var (first, second) in items)
{
VoidMethodThatThrows(first, second);
}
Furthermore, .NET Core and 5 adds an overload which automatically pairs the values into tuples so you don't have to do that mapping.
var items = collection1.Zip(collection2); // IEnumerable<(Type1, Type2)>
.NET 6 adds a third collection to the mix.
var items = collection1.Zip(collection2, collection3); // IEnumerable<(Type1, Type2, Type3)>
I often need to execute an action on each pair in two collections. The Zip method is not useful in this case.
This extension method ForPair can be used:
public static void ForPair<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second,
Action<TFirst, TSecond> action)
{
using (var enumFirst = first.GetEnumerator())
using (var enumSecond = second.GetEnumerator())
{
while (enumFirst.MoveNext() && enumSecond.MoveNext())
{
action(enumFirst.Current, enumSecond.Current);
}
}
}
So for your example, you could write:
var collection1 = new List<int>() { 1, 2 };
var collection2 = new List<int>() { 3, 4 };
collection1.ForPair(collection2, VoidMethodThatThrows);

Categories

Resources