Returning 2 arrays from a function - c#

I create 2 jagged arrays inside my function:
double[][] x = new double[i][];
double[][] y = new double[j][];
I perform some sort of operations on them, and want to return both of them as a result of the function. How can I do that?

Well you could return an array of jagged arrays: double[][][]
public double[][][] GetData(int i, int j)
{
double[][] x = new double[i][];
double[][] y = new double[j][];
return new [] {x, y};
}
but it may make more sense to define a class to give the results context. If you return two arrays what do they mean? Are they always in the same order? By just returning an array you leave a lot for the consumer to learn about the meaning of the return type. A class, on the other hand, would provide context:
public TwoArrays GetData(int i, int j)
{
double[][] x = new double[i][];
double[][] y = new double[j][];
return new TwoArrays {X = x, Y = y};
}
public class TwoArrays
{
public double[][] X {get; set;}
public double[][] Y {get; set;}
}

Tuples are a completely valid option as well. Some folks don't like them as a matter of opinion, and they're NOT great options for public APIs, but they're useful without adding yet another class to your namespace. You can go overboard with them, and four- and five-tuples exceed even my tolerance for them
double[][] x = new double[i][];
double[][] y = new double[j][];
// Work your magic
return new Tuple<double[][], double[][]>(x, y);
Item1 and Item2 will now be your double[][] arrays.

Related

Trying to sort a list full of a object by the a list from that object's properties c#

I have a class that has a bunch of different variables and a couple lists 1 in particular holds ints(positionInts)
I also have a list(teamsList) for holding objects I have created from that class
now I would like to sort the team's list by positions values
Hopefully, I'm not being too vague as the project I'm working on is full of not well-written code so it can be hard to explain.
This function orders the list according to your precondition.
private List<String> OrderList(List<String> teams, int[] positions)
{
List<String> orderedTeams;
Dictionary<int, string> teamsToOrder = new Dictionary<int, string>();
int position = 0;
foreach (string team in teams)
{
teamsToOrder.Add(positions[position], teams[position]);
position = position + 1;
}
orderedTeams = teamsToOrder.OrderByDescending(team => team.Key).Select(team => team.Value).ToList();
return orderedTeams;
}
If I understand your question correctly, then you have list of arbitrary type, for example list of strings:
var teamsList = new List<String> { "team1", "team2", "team3", "team4" };
Next up, you have enumeration of integers:
var positionInts = new[] { 2, 3, 1, 0 };
And your goal is to order teamsList based on sequence numbers of the positionInts. In that case you can use following method:
static IEnumerable<T> OrderBySequence<T>(IEnumerable<T> source, IEnumerable<Int32> sequence)
{
for (var i = 0; i < Math.Min(source.Count(), sequence.Count()); i++)
{
var s = sequence.ElementAt(i);
if (s > -1 && s < source.Count())
{
yield return source.ElementAt(s);
}
}
}
Which will produce:
team3
team4
team2
team1

Creating a data structure with 1 key, 2 values in C# and also retrieving values for a particular key

I want to create a data structure with 1 key,2 values,which looks like this:
List<KeyValuePair<double, double, double>> list = new List<KeyValuePair<double, double, double>>();
I basically have x,y,z coordinate values and I want to keep on appending them in a data structure.After,appending the data,I would like to retrieve all the available "x"(something like "List").For each value of x,I want to find the multiple "y" values.And then for a particular "x" and "y" value,I would like to find all the multiple "z" values.
For e.g: if I have coordinates like (1,2,3) ; (1,3,4) ; (1,2,6); (1,2,9)
For a value of 1,I want to retrieve 2 and 3. Likewise,for a value of 1,2 ; I want to retrieve the values 6 and 9.
I would be really glad,if someone can let me know the procedure to do this in C#.
Thanks in Advance.
You don't have unique keys and you have keys of varying width, so a dictionary nor a KeyValuePair are going to help you.
If, when looking up single values (the X of (X, Y, Z)), you are only interested in Y and never Z, you could pad the key with an unused value and store the records twice (so the key-value-pairs of (1, 2, 3) become (0, 1, 2) and (1, 2, 3)), but that won't really make things clearer.
You could store the records in a List<Tuple<double, double, double>>:
var list = new List<Tuple<double, double, double>>
{
Tuple.Create<double, double, double>(1,2,3),
Tuple.Create<double, double, double>(1,3,4),
Tuple.Create<double, double, double>(1,2,6),
Tuple.Create<double, double, double>(1,2,9),
};
var search = 1d;
var results = list.Where(t => t.Item1 == search)
.Select(t => t.Item2);
Then when you want to search on two values, utilize a tuple as well:
var search = Tuple.Create<double, double>(1, 2);
var results = list.Where(t => t.Item1 == search.Item1 && t.Item2 == search.Item2)
.Select(t => t.Item3);
Basically the answer of CodeCaster, but with methods (I took the time creating it, but he was faster :))
public void TestMethod()
{
List<Tuple<double, double, double>> list = new List<Tuple<double, double, double>>();
list.Add(new Tuple<double, double, double>(1, 2, 3));
list.Add(new Tuple<double, double, double>(1, 2, 5));
list.Add(new Tuple<double, double, double>(8, 2, 3));
list.Add(new Tuple<double, double, double>(1, 5, 3));
var x = GetIt(1, list);
var y = GetIt(1, 2, list);
}
public List<double> GetIt(double d, List<Tuple<double, double, double>> list)
{
return (from a in list
where a.Item1 == d
select a.Item2).Distinct().ToList();
}
public List<double> GetIt(double d, double e, List<Tuple<double, double, double>> list)
{
return (from a in list
where a.Item1 == d && a.Item2 == e
select a.Item3).Distinct().ToList();
}
There are multiple approachs to what you want. If you're using VS2017+, you could use Value Tuple (native when targetting .NET4.7, otherwise available in Nuget)
var list = new List<(double x, double y, double z)>();
list.Add((1,2,3));
list.Add((1,3,4));
list.Add((1,2,6));
list.Add((1,2,9));
And use Linq to group by x, y, and z.
To retrieve all y with x=1
var l1 = list.Where(i=>i.x==1).Select(i=>i.y);
To retrieve all z with x=1 and y=2
var l2 = list.Where(i=>i.x==1 && i.y==2).Select(i=>i.z);
I wouldn't recommend a Dictionary type approach because what you're trying to store are 3 values, not a key and a value.
I'd recommend the follow:
Create a class Coordinates
Make a list of said class
Use LINQ to go through it.
For example:
public class Coordinates
{
public float XCoord { get; set; }
public float YCoor { get; set; }
public float ZCoor { get; set; }
}
Then you can create a list and use LINQ to select the needed data, in this example I created a function that accepts X,Y, and Z to filter the list.
List<Coordinates> list = new List<Coordinates>(); //Populate the list
Then with the following method:
public List<Coordinates> SelectCoords(List<Coordinates> originalList, float? X, float? Y,float? Z)
{
List<Coordinates> filteredList = new List<Coordinates>(originalList);
if (X != null)
{
filteredList = filteredList.Where(v => v.XCoord == X).ToList();
}
if (Y != null)
{
filteredList = filteredList.Where(v => v.YCoord == Y).ToList();
}
if (X != null)
{
filteredList = filteredList.Where(v => v.ZCoord == Z).ToList();
}
return filteredList;
}
Lets you choose how to filter the list only returning the list with X,Y, and or Z
list = SelectCoords(list, 1, 2,null);
Ms got your back and have a class for this just in case : Point3D structure.
Pros: It has a number of build in method that can be use full. And you can play around with point and vector.
Cons: It's overkill if you simply store those 3 double.

Generate all possible coverage options

Suppose I have 2 lists: one containing strings, one containing integers, they differ in length. The application I am building will use these lists to generate combinations of vehicle and coverage areas. Strings represent area names and ints represent vehicle ID's.
My goal is to generate a list of all possible unique combinations used for further investigation. One vehicle can service many areas, but one area can't be served by multiple vehicles. Every area must receive service, and every vehicle must be used.
So to conclude the constraints:
Every area is used only once
Every vehicle is used at least once
No area can be left out.
No vehicle can be left out
Here is an example:
public class record = {
public string areaId string{get;set;}
public int vehicleId int {get;set;}
}
List<string> areas = new List<string>{ "A","B","C","D"};
List<int> vehicles = new List<int>{ 1,2};
List<List<record>> uniqueCombinationLists = retrieveUniqueCombinations(areas,vehicles);
I just have no clue how to make the retrieveUniqueCombinations function. Maybe I am just looking wrong or thinking too hard. I am stuck thinking about massive loops and other brute force approaches. An explanation of a better approach would be much appreciated.
The results should resemble something like this, I think this contains all possibilities for this example.
A1;B1;C1;D2
A1;B1;C2;D1
A1;B2;C1;D1
A2;B1;C1;D1
A2;B2;C2;D1
A2;B2;C1;D2
A2;B1;C2;D2
A1;B2;C2;D2
A2;B1;C1;D2
A1;B2;C2;D1
A2;B2;C1;D1
A1;B1;C2;D2
A2;B1;C2;D1
A1;B2;C1;D2
Here's something I threw together that may or may not work. Borrowing heavily from dtb's work on this answer.
Basically, I generate them all, then remove the ones that don't meet the requirements.
List<string> areas = new List<string> { "A", "B", "C", "D" };
List<int> vehicles = new List<int> { 1, 2 };
var result = retrieveUniqueCombinations(areas, vehicles);
result.ToList().ForEach((recordList) => {
recordList.ToList().ForEach((record) =>
Console.Write("{0}{1};", record.areaId, record.vehicleId));
Console.WriteLine();
});
public IEnumerable<IEnumerable<record>> retrieveUniqueCombinations(IEnumerable<string> areas, IEnumerable<int> vehicles)
{
var items = from a in areas
from v in vehicles
select new record { areaId = a, vehicleId = v };
var result = items.GroupBy(i => i.areaId).CartesianProduct().ToList();
result.RemoveAll((records) =>
records.All(record =>
record.vehicleId == records.First().vehicleId));
return result;
}
public class record
{
public string areaId { get; set; }
public int vehicleId { get; set; }
}
static class Extensions
{
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }));
}
}
This produces the following:
A1;B1;C1;D2;
A1;B1;C2;D1;
A1;B1;C2;D2;
A1;B2;C1;D1;
A1;B2;C1;D2;
A1;B2;C2;D1;
A1;B2;C2;D2;
A2;B1;C1;D1;
A2;B1;C1;D2;
A2;B1;C2;D1;
A2;B1;C2;D2;
A2;B2;C1;D1;
A2;B2;C1;D2;
A2;B2;C2;D1;
Note that these are not in the same order as yours, but I'll leave the verification to you. Also, there's likely a better way of doing this (for instance, by putting the logic in the RemoveAll step in the CartesianProduct function), but hey, you get what you pay for ;).
So lets use some helper classes to convert numbers to IEnumerable<int> enumerations in different bases. It may be more efficient to use List<> but since we are trying to use LINQ:
public static IEnumerable<int> LeadingZeros(this IEnumerable<int> digits, int minLength) {
var dc = digits.Count();
if (dc < minLength) {
for (int j1 = 0; j1 < minLength - dc; ++j1)
yield return 0;
}
foreach (var j2 in digits)
yield return j2;
}
public static IEnumerable<int> ToBase(this int num, int numBase) {
IEnumerable<int> ToBaseRev(int n, int nb) {
do {
yield return n % nb;
n /= nb;
} while (n > 0);
}
foreach (var n in ToBaseRev(num, numBase).Reverse())
yield return n;
}
Now we can create an enumeration that lists all the possible answers (and a few extras). I converted the Lists to Arrays for indexing efficiency.
var areas = new List<string> { "A", "B", "C", "D" };
var vehicles = new List<int> { 1, 2 };
var areasArray = areas.ToArray();
var vehiclesArray = vehicles.ToArray();
var numVehicles = vehiclesArray.Length;
var numAreas = areasArray.Length;
var NumberOfCombos = Convert.ToInt32(Math.Pow(numVehicles, numAreas));
var ansMap = Enumerable.Range(0, NumberOfCombos).Select(n => new { n, nd = n.ToBase(numVehicles).LeadingZeros(numAreas)});
Given the enumeration of the possible combinations, we can convert into areas and vehicles and exclude the ones that don't use all vehicles.
var ans = ansMap.Select(nnd => nnd.nd).Select(m => m.Select((d, i) => new { a = areasArray[i], v = vehiclesArray[d] })).Where(avc => avc.Select(av => av.v).Distinct().Count() == numVehicles);

Adding/summing two arrays

I've encountered a purely hypothetical problem which feels like it has an easy solution if I find the right linq method...
I have two arrays of ints and I know they are the same size. I want to create a third array of the same size where the elements in the third array are the sum of the elements in the first two arrays in the corresponding position.
Below is a method that should show what I want to do.
public static int[] AddArrays(int[] a, int[] b)
{
int[] newArray = new int[a.Length];
for (int i = 0; i<a.Length; i++)
{
newArray[i]=a[i]+b[i];
}
return newArray;
}
Are there any Linq methods that I can just use like
return a.DoStuff(b, (x,y) => x+y)
or something like that?
I should note that this probably falls in the category of homework since the original problem came from a website I was looking at (though I can't find a direct link to the problem) and not as a question I need for work or anything.
If no simple method exists then what is the most Linqy way to do this? an array.each would seem to have the problem of not being able to index the second array easily to add the values to the one you are iterating through leading me to wonder if Linq would be any help at all in that situation...
Zip it :)
var a = new int[] {1,2,3 };
var b = new int[] {4,5,6 };
a.Zip(b, (x, y) => x + y)
You can use the Select method.
int[] a = new[] { 1, 2, 3 };
int[] b = new[] { 10, 20, 30 };
var c = a.Select ((x, index) => x + b[index]).ToArray();
public static int[] AddArrays(int[] a, int[] b)
{
return a.Zip(b, (x,y) => x+y).ToArray();
}
IList<int> first = new List<int> { 2, 3, 4, 5 };
IList<int> second = new List<int> { 2, 3, 4, 5 };
var result = Enumerable.Zip(first, second, (a, b) => a + b);
Without LINQ:
private static IEnumerable<int> AddArrays(IEnumerable<int> a1, IEnumerable<int> a2)
{
var e1 = a1.GetEnumerator();
var e2 = a2.GetEnumerator();
while (e1.MoveNext() && e2.MoveNext())
yield return e1.Current + e2.Current;
}
If you have an IEnumerable<int[]> arrayCollection to sum:
arrayCollection.Aggregate((a,b) => a.Zip(b, (x,y) => x + y).ToArray())

Getting the "diff" between two arrays in C#?

Let's say I have these two arrays:
var array1 = new[] {"A", "B", "C"};
var array2 = new[] {"A", "C", "D"};
I would like to get the differences between the two. I know I could write this in just a few lines of code, but I want to make sure I'm not missing a built in language feature or a LINQ extension method.
Ideally, I would end up with the following three results:
Items not in array1, but are in array2 ("D")
Items not in array2, but are in array1 ("B")
Items that are in both
If you've got LINQ available to you, you can use Except and Distinct. The sets you asked for in the question are respectively:
- array2.Except(array1)
- array1.Except(array2)
- array1.Intersect(array2)
from the MSDN 101 LINQ samples....
public void Linq52() {
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
IEnumerable<int> aOnlyNumbers = numbersA.Except(numbersB);
Console.WriteLine("Numbers in first array but not second array:");
foreach (var n in aOnlyNumbers) {
Console.WriteLine(n);
}
}
Here are the benchmarks of LINQ extension methods. The results were obtained during the development of a real program.
The tests:
2 lists (lst1 and lst2) each approximately 250000 objects. Each object (class Key) contains a string and an integer. The second list mostly contains the same entries as the first one, but some new entries are added and some are removed.
I tested the Except extension method.
var except = lst2.Except(lst1);
List lst = except.ToList();
These 2 lines produced 600 items list of “new additions”. I timed it using the StopWatch object. The speed is astonishing:220 ms. The computer I used is by no means a “speedy Gonzales”. Core 2 Duo T7700 – 2.4GHz.
Note:
Here is the class Key, which implements IEquatable i-face.
public class Key : IEquatable<Key>
{
public int Index { get; private set; }
public string Name { get; private set; }
public Key(string keyName, int sdIndex)
{
this.Name = keyName;
this.Index = sdIndex;
}
// IEquatable implementation
public bool Equals(Key other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null)) return false;
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other)) return true;
//Check whether the products' properties are equal.
return Index.Equals(other.Index) && Name.Equals(other.Name);
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public override int GetHashCode()
{
//Get hash code for the name field if it is not null.
int hashKeyName = Name == null ? 0 : Name.GetHashCode();
//Get hash code for the index field.
int hashKeyIndex = Index.GetHashCode();
//Calculate the hash code for the Key.
return hashKeyName ^ hashKeyIndex;
}
}
I've had to do things similar to this with very large sets of data. If you're dealing with a few thousand or so, use the Linq stuff since it's much clearer. But if you know that your arrays are pre-sorted, running a merge like this can do it significantly faster, since it only makes one pass through the data and doesn't need to allocate as much memory as the Linq version.
int iA = 0;
int iB = 0;
List<int> inA = new List<int>();
List<int> inB = new List<int>();
List<int> inBoth = new List<int>();
while (iA < numbersA.Length && iB < numbersB.Length)
{
if (numbersA[iA] < numbersB[iB])
{
inA.Add(numbersA[iA++]);
}
else if (numbersA[iA] == numbersB[iB])
{
inBoth.Add(numbersA[iA++]);
++iB;
}
else
{
inB.Add(numbersB[iB++]);
}
}
while (iA < numbersA.Length)
{
inA.Add(numbersA[iA++]);
}
while (iB < numbersB.Length)
{
inB.Add(numbersB[iB++]);
}
Again, this is really only needed if you are dealing with hundreds of thousands of values.
Another solution would be like below as well
int[] arr1 = new int[] { 45, 26, 99, 55, 36 };
int[] arr2 = new int[] { 45, 26, 99, 20, 36 };
var res = arr1.Union(arr2).Except(arr1.Intersect(arr2));

Categories

Resources