Convert array to tuple?
Asked Answered
H

6

18

Is it possible to convert array to tuple in C#? Something like this:

var ar = new int[2] {5, 7};
Tuple<int,int> t = Tuple.Create(ar);
Howze answered 6/6, 2017 at 9:34 Comment(3)
If you know the size of you array you can just pass the values of ar[0], ar[1]Dropsonde
This only makes sense if you know the size of the array in advance. Then using C#7 you can do this: (int a, int b) = (ar[0], ar[1]); (which has the advantage that you can name the tuple elements).Jahncke
The main problem here is that the size of the array (and the size of the Tuple<>) must be known at compile time: in the code you wrote, you explicitly wrote Tuple<int, int>. You can easily create a method that, given an array of two (or more) elements, returns a Tuple<T, T>.Nonsuch
H
4

No, System.Tuple has a maximum size for good reason. It's simply the wrong tool for the job you appear to be doing. Why don't you just return the array instead of a tuple? Your approach could end up needing a tuple with dozens of elements which is beyond ridiculous and not at all maintainable.

Even better instead of returning the array, return an interface such as ICollection<T> or IEnumerable<T>.

Heimer answered 6/6, 2017 at 9:39 Comment(2)
not at all maintainable - just what I wanted to sayEveliaevelin
I think the questioner may have been thinking of cases where the array size is known at compile time. For example an older API predating tuples that returns an array of four strings. Or if you have done a regular expression match with a known number of capturing fields, and now want to package up the result as a tuple.Denver
A
13

Now with C# 7.0, you can create extension methods to deconstruct arrays to ValueTuple, which makes

var (p1,p2,p3) = s.Split(':');

possible.

public static class ArrayExt {
    public static void Deconstruct<T>(this T[] srcArray, out T a0) {
        if (srcArray == null || srcArray.Length < 1)
            throw new ArgumentException(nameof(srcArray));

        a0 = srcArray[0];
    }

    public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1) {
        if (srcArray == null || srcArray.Length < 2)
            throw new ArgumentException(nameof(srcArray));

        a0 = srcArray[0];
        a1 = srcArray[1];
    }

    public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2) {
        if (srcArray == null || srcArray.Length < 3)
            throw new ArgumentException(nameof(srcArray));

        a0 = srcArray[0];
        a1 = srcArray[1];
        a2 = srcArray[2];
    }

    public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3) {
        if (srcArray == null || srcArray.Length < 4)
            throw new ArgumentException(nameof(srcArray));

        a0 = srcArray[0];
        a1 = srcArray[1];
        a2 = srcArray[2];
        a3 = srcArray[3];
    }

    public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3, out T a4) {
        if (srcArray == null || srcArray.Length < 5)
            throw new ArgumentException(nameof(srcArray));

        a0 = srcArray[0];
        a1 = srcArray[1];
        a2 = srcArray[2];
        a3 = srcArray[3];
        a4 = srcArray[4];
    }

    public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3, out T a4, out T a5) {
        if (srcArray == null || srcArray.Length < 6)
            throw new ArgumentException(nameof(srcArray));

        a0 = srcArray[0];
        a1 = srcArray[1];
        a2 = srcArray[2];
        a3 = srcArray[3];
        a4 = srcArray[4];
        a5 = srcArray[5];
    }

    public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3, out T a4, out T a5, out T a6) {
        if (srcArray == null || srcArray.Length < 7)
            throw new ArgumentException(nameof(srcArray));

        a0 = srcArray[0];
        a1 = srcArray[1];
        a2 = srcArray[2];
        a3 = srcArray[3];
        a4 = srcArray[4];
        a5 = srcArray[5];
        a6 = srcArray[6];
    }

    public static void Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2, out T a3, out T a4, out T a5, out T a6, out T a7) {
        if (srcArray == null || srcArray.Length < 8)
            throw new ArgumentException(nameof(srcArray));

        a0 = srcArray[0];
        a1 = srcArray[1];
        a2 = srcArray[2];
        a3 = srcArray[3];
        a4 = srcArray[4];
        a5 = srcArray[5];
        a6 = srcArray[6];
        a7 = srcArray[7];
    }
}
Arty answered 26/1, 2021 at 2:7 Comment(3)
Is Deconstruct implicitly called based on usage? E.g. since LHS is (p1,p2,p3), does it then check if the class has a method or extension method with 3 out parameters or do you need to call something like ´s.Split(':').Deconstruct();`?Overshoe
Or it looks like it must be called Deconstruct specifically: deconstruct#user-defined-typesOvershoe
@Overshoe You must explicitly define the method, but it is called implicitly when you use your user defined type (or other type with an extension method) in a deconstruct context: var arr = new[] { 1, 2, 3 }; var (a1,a2,a3) = arr; will call Deconstruct<T>(this T[] srcArray, out T a0, out T a1, out T a2) implicitly.Arty
H
4

No, System.Tuple has a maximum size for good reason. It's simply the wrong tool for the job you appear to be doing. Why don't you just return the array instead of a tuple? Your approach could end up needing a tuple with dozens of elements which is beyond ridiculous and not at all maintainable.

Even better instead of returning the array, return an interface such as ICollection<T> or IEnumerable<T>.

Heimer answered 6/6, 2017 at 9:39 Comment(2)
not at all maintainable - just what I wanted to sayEveliaevelin
I think the questioner may have been thinking of cases where the array size is known at compile time. For example an older API predating tuples that returns an array of four strings. Or if you have done a regular expression match with a known number of capturing fields, and now want to package up the result as a tuple.Denver
F
-1

By doing this you can get an list of tuples but I don't see the reason to do this:

      var ar = new int[2] { 5, 7 };

        List<Tuple<int>> result = ar
            .Select(x => Tuple.Create(x))
            .ToList();

Or if you want to have it in one tuple instead:

   var ar = new int[2] { 5, 7 };
    Tuple<int[]> result = Tuple.Create(ar);

If you know the size do this:

  Tuple<int, int> tuple = Tuple.Create(ar[0], ar[1]);
Farfamed answered 6/6, 2017 at 9:39 Comment(0)
A
-1

Well why don't we do it like this

public static Tuple<T, T> CreateTuple<T>(T[] array, int totalItem = 2)
{
    if (arr.length % totalItem != 0)
        throw new Exception("Error the length does not correlate with totalItem");
    
    return Tuple.Create(arr);
}

Here we validate that each item have one and two.

Alrich answered 5/2, 2018 at 13:56 Comment(2)
There can be very good situations where you would like to do this, like when the array size is known. So saying in general this is a bad idea is a bit harsh.Mohenjodaro
This could produces a compiler error: Error CS0029: Cannot implicitly convert type 'System.Tuple<T[]>' to 'System.Tuple<T, T>'Sanskrit
P
-1

you can use sub tuples like, for example this

var tupArray = new Tuple<dynamic,dynamic,dynamic,dynamic,dynamic,dynamic,dynamic,Tuple<dynamic,dynamic>>
(
    a[0],a[1],a[2],a[3],a[4],a[5],a[6],new Tuple<dynamic,dynamic>(a[7],a[8])
)
Plurality answered 16/6, 2021 at 19:32 Comment(0)
N
-3

your idea is a bad idea... array and tuples don't "mix" in C#/.NET. There are languages where the distance between arrays and classes is small (like Javascript, where with the [...] operator you can use both arrays and objects). C# isn't one of those languages. Tuples don't define a this[int n] indexer for exactly this reason.

But you asked for code, and so I'll give you code.

The main problem here is that the size of the array (and the size of the Tuple<>) must be known at compile time: in the code you wrote, you explicitly wrote Tuple<int, int>. You can easily create a method that, given an array of two (or more) elements, returns a Tuple<T, T>, like:

public static Tuple<T, T> CreateTuple2<T>(T[] array)
{
    if (array == null || array.Length < 2)
    {
        throw new ArgumentException(nameof(array));
    }

    return Tuple.Create(array[0], array[1]);
}

From this you can create other CreateTuple3(), CreateTuple4()...

Nonsuch answered 6/6, 2017 at 10:11 Comment(6)
This is terrible advice.Heimer
@Heimer I consider it to be an "anwer", not an "advice". The "question" is bad (mixing arrays and tuples is a bad idea in C#/.NET), but he asked for a piece of code (Is it possible to convert array to tuple in C#? Something like this:), so I gave it to him.Nonsuch
Purely theoretically, size of Tuple<> doesn't need to be known: you can make a single method that builds the Tuple<,,,,,,> dynamically via reflection sizing it according to the array's size (assuming it doesn't exceed the tuple's max N params) and returns it as object or dynamic and laugh evilishly at future woes of its users (oh, you got object? so just cast it muahahaha). Or create a single TTuple CreateTuple<TTuple>(object[] vals) that works in a similar way, and laugh evilishly in a similar way (just invoke it CreateTuple<Tuple<int,string,int,... >..).. or, (...)Eveliaevelin
@Eveliaevelin Yes... And all of them would probably be even more stupid than wanting to convert an array to a tuple :-)Nonsuch
And yet I would like to do var (p1,p2,p3) = str.Split(':');Arty
And now I want to implement Perl's unpack in C# and be able to use it with Tuple assignment just like Perl does: var (s1,s2) = unpack("A4x2A4", test);Arty

© 2022 - 2024 — McMap. All rights reserved.