List<Tuple<T>> | AddRange with arrays - c#

Im wondering about how to add arrays to a List<Tuple<double, double>>.
My (short) code:
double[] var1 = new double[5] { 1, 2, 3, 4, 5 };
double[] var2 = new double[5] { 1.5, 1.5, 2.5, 1.2, 1.1 };
List<Tuple<double, double>> tup = new List<Tuple<double, double>>();
I would like to fill tup with my arrays. Unfortunately for that I would need to instanciate a Tuple for each entry. Dont know how to do this.
In general I could just use a loop, but this looks dirty for me. My question is about performance and clean code.
if(var1.Length == var2.Length)
{
for (int i = 0; i < var1.Length; i++)
{
tup.Add(new Tuple<double, double>(var1[i], var2[i]));
}
}
Isnt there a shorter way to archive this? Any way with AddRange maybe?

You could use LINQ's Enumerable.Zip extension method. Per the docs, this:
Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.
In this case, we can use Tuple.Create as the function to create a tuple from both elements.
var tup = var1.Zip(var2, Tuple.Create).ToList();
Though note that this could give a slightly different result to your code in the case where the sequences are not the same length. Per the docs again:
If the input sequences do not have the same number of elements, the method combines elements until it reaches the end of one of the sequences
Check out this fiddle for a working demo.

Well, you could use Zip to project the collections to a list of tuples:
var tup = var1.Zip(var2, (v1, v2) => new Tuple<double, double>(v1,v2))
.ToList();
But personally I find your original method easier to read and to understand the intent. There should be very little performance difference. Shorter code isn't always better code.

You have to loop yourself or let LINQ loop, Enumerable.Zip joins by index:
List<Tuple<double, double>> tup = var1.Zip(var2, (d1, d2) => Tuple.Create(d1, d2))
.ToList();
So this isn't more efficient but might be more readable.

Related

Get array consisting of first values of a list of tuples

In my C# code I have a list of Tuples. The tuples themselves consist of two numbers of the type double and an object of type LocalDate.
List<Tuple<double, double, LocalDate>> tupleList = new List<Tuple<double, double, LocalDate>>();
The list, for instance, could look as follows.
1, 10, LocalDate1
12, 310, LocalDate2
31, 110, LocalDate3
What is an elegant way to create an array of doubles that only contains the first double values of each list item?
Accordingly, I want an ArrayList that only consists of the LocalDate objects in the list. The order should be preserved.
The expected result should be:
double[] => [1, 12, 31]
double[] => [10, 310, 110]
ArrayList<> => [LocalDate1, LocalDate2, LocalDate3]
I am aware that the ordinary way would be to iterate over the list in a for loop and create the arrays via this loop. However, I think that there should be a more concise and elegant way.
Linq would be the way to go:
var firstValues = tupleList.Select(x => x.Item1).ToList();
This projects the list of Tuples into a list of the first items only, keeping their order. Same with the second, third, n'th item as well.
If you want an array, just invoke ToArray() instead of ToList().
This can be done with a baseline for loop:
//Sorry for any Syntax errors. Got no VS installation in reach
double[] output = new double[tupleList.Length];
for(int i = 0; i < tupleList.Length; i++){
output[i] = tupleList[i].Item1;
}
Of course something like linq or anything that uses lambdas in general might be more modern. But I doubt it is faster or more memory efficient. It has to use a List of some sort and create an array from that.

What is the most compact and/or efficient way to extract multiple (non-consecutive) values from a list using indexing

I have the following list:
List<int> listOfInt = new List<int> {10, 20, 30, 40, 50};
I am now given a list of indices pointing to the values to be extracted from listOfInt:
int[] idxList= new int[] { 2, 4, 1 };
Now, I want to extract all the values from listOfInt by index (as per provided idxList) into another list.
Here is what I came up with, which seems to work, but I would like to get rid of this foreach loop. How can this be done?
List<int> newList= new List<int>();
foreach(var idx in idxList) newList.Add( listOfInt.ElementAt(idx) );
Solution:
{30, 50, 20} will be written into newList
Well, it depends, can we do more efficient without the foreach loop?
foreach() gets an enumerator and walks over the list. Any other solution you can come up with, will ultimately have to do the same, because you need to handle each item in your index list.
So no, you can't make this more efficient. Or maybe you could, if you write out all requirements and assumptions, but no way this is going to be the performance bottleneck of your code.
CPU cycles are cheap. Terse code is expensive, to both write and read, because of the mental overhead.
You could use Linq as #Sohaib demonstrates below, but that won't be noticeably more efficient.
Short way to do this, using Linq: idxList.Select(i => listOfInt[i]).ToList()
If you want to omit foreach you can use this:
var result = idxList.Select(i => listOfInt.ElementAt(i));
You are adding items to newList one by one. This will create some unnecessary memory allocations. Better to give new List hint about resulting size.
var listOfInt = new List<int> { 10, 20, 30, 40, 50 };
var idxList = new [] { 2, 4, 1 };
var newList = new List<int>(idxList.Length);
for (int i = 0; i < idxList.Length; i++)
newList[i] = listOfInt[idxList[i]];
Also, for loop tends to be faster than foreach when iterating thru List (source).

Swap array keys and values in C# in a functional-programming compatible way

Suppose I have the following C# code:
var array = new []{3, 2, 5, 4, 1, 0};
var converted = new int[array.Length];
for (var i = 0; i < array.Length; i++) {
converted[array[i]] = i;
}
Then, at the end, we have converted == new {5, 4, 1, 0, 3, 2};. However, "for loops are evil", so I can rewrite it as follows:
var array = new []{3, 2, 5, 4, 1, 0};
var converted = new int[array.Length];
array
.Select((value, index) => new {index, value})
.ToList()
.ForEach(o => converted[o.value] = o.index);
However, we still have a mutated-state-situation. Does Linq provide a nice way to do this, without increasing the asymptotic complexity?
I know that I can sort based on the values, or use some sort of searching technique, but in both cases, the complexity becomes O(n log n) or more.
EDIT: I know that at least the second one is ugly. The first one is how these type of things are done usually, but in almost every case, LINQ provides a nicer and better-understandable way than a for loop. Therefore, I was wondering whether there was a way to do this with LINQ.
Your for loop is fine. Don't change it. Sometimes it's better to do stuff procedurally while other times it is better to do it functionally. In this case, procedural is better.
Just look at what a horrible mess this would be if done functionally:
// assuming the values are all members of the set of natural numbers from 0 to (array.Length - 1)
var converted = array.Select((x, i) => new { Index = i, Element = x })
.OrderBy(x => x.Element)
.Select(x => x.Index).ToList();
That is a lot less readable than the procedural version.

Different kind of concatenate two arrays in c#

I have two lists posted from view to controller such as
int[] blablaIds = { 13, 377, 1002 };
int[] secondBlaBlaIds = { 7, 18, 126 };
For some reason I want to explicitly combine these as
int[] combinedIds = { { 7, 13 }, {18, 377}, {126, 1002} }
Is it possible with LINQ?
There's no such thing as a list of long or int you're going to have to pick one and then convert the other list to the correct datatype. Once they're the same datatype you can easily concat the two lists.
longIds.Concat(intIds.Cast<long>());
As Jon Skeet has identified in the comments your question is incredibly difficult to answer in its current form. If you're looking to create a paired list of items from the first and second you could try using .Zip. You're still going to have to do some casting if you want ints and longs to coexist in the same collection. Here's an example (not verified with IDE).
var zipped = firstIds.Zip(secondIds, (first, second) => new List<long> {first, (long) second});
Have a look at SelectMany. It's rather powerful and should provide the functionality you are looking for.

Sorting two arrays (values,keys), then sorting the keys

I have what seems to be a simple problem but I can't figure it out so far.
Say I have two arrays:
int[] values = {10,20,20,10,30};
int[] keys = {1,2,3,4,5};
Array.Sort(values,keys);
Then the arrays would look like this:
values = {10,10,20,20,30};
keys = {4,1,2,3,5};
Now, what I want to do is make it so that the keys are also sorted in second priority so the key array to look like this:
keys = {1,4,2,3,5};
Notice the 1 and 4 values are switched and the order of the value array has not changed.
If an "in-place sorting" is not strictly necessary for you, I suggest to use OrderBy:
var sortedPairs = values.Select((x, i) => new { Value = x, Key = keys[i] })
.OrderBy(x => x.Value)
.ThenBy(x => x.Key)
.ToArray(); // this avoids sorting 2 times...
int[] sortedValues = sortedPairs.Select(x => x.Value).ToArray();
int[] sortedKeys = sortedPairs.Select(x => x.Key).ToArray();
// Result:
// sortedValues = {10,10,20,20,30};
// sortedKeys = {1,4,2,3,5};
Generally, parallel arrays are frowned upon. It is very easy for the data to become out of sync. What I would suggest is either using a map/Dictionary data type, or storing the keys and values in a single object, and then having an array of said objects.
Edit: after re-reading your question, I dont' think the Dictionary is the data type you want, based on your need to sort the values. I would still suggest having an object that contains the keys and values, however. You can then sort by the values, and rest assured that they keys aren't out of sync.
Array.Sort(values,keys) will use the default Comparer to sort the values and keys. You would need to write a custom Comparer to do what you're describing, and pass your Comparer in to the Array.Sort method.
By converting this to a sort on an array of value pairs you can supply your own comparator and make the sort work pretty much any way you like. (It seems awful risky to use two separate arrays.) See the fourth method at http://msdn.microsoft.com/en-us/library/system.array.sort.aspx.
I think the accepted answer is great. One can use anonymous types, as shown in that answer, or declare a named type to hold the data while sorting.
Even better, declare a named type to hold the data all the time. Parallel arrays are usually not a good idea. There are some niche scenarios where they are needed for performance or interopability reasons, but otherwise they should be avoided.
That said, for completeness I think it would be useful to also point out that the arrays can be sorted "by proxy". I.e. create a new array that is just the indexes of the original arrays and sort that array. Once the index array has been sorted, you can use that array to access the original data directly, or you can use that array to then copy the original data into new, sorted arrays.
For example:
static void Main(string[] args)
{
int[] values = { 10, 20, 20, 10, 30 };
int[] keys = { 1, 2, 3, 4, 5 };
int[] indexes = Enumerable.Range(0, values.Length).ToArray();
Array.Sort(indexes, (i1, i2) => Compare(i1, i2, values, keys));
// Use the index array directly to access the original data
for (int i = 0; i < values.Length; i++)
{
Console.WriteLine("{0}: {1}", values[indexes[i]], keys[indexes[i]]);
}
Console.WriteLine();
// Or go ahead and copy the old data into new arrays using the new order
values = OrderArray(values, indexes);
keys = OrderArray(keys, indexes);
for (int i = 0; i < values.Length; i++)
{
Console.WriteLine("{0}: {1}", values[i], keys[i]);
}
}
private static int Compare(int i1, int i2, int[] values, int[] keys)
{
int result = values[i1].CompareTo(values[i2]);
if (result == 0)
{
result = keys[i1].CompareTo(keys[i2]);
}
return result;
}
private static int[] OrderArray(int[] values, int[] indexes)
{
int[] result = new int[values.Length];
for (int i = 0; i < values.Length; i++)
{
result[i] = values[indexes[i]];
}
return result;
}

Categories

Resources