Solved

LINQ help

Posted on 2014-10-03
10
137 Views
Last Modified: 2016-02-15
Hi, I thought I understood LINQ.

I do not.

Below is some code I have written to try to get a distinct list of strings. It doesn't even compile. Can someone please help me get it right?

Thank you

John

using System;
using System.Linq;

namespace ConsoleApplication41
{
    public class Test0
    {
        public String[] Names { get; set; }
        public int id { get; set; }
    }

    public class Test1
    {
        public Test0[] Tests { get; set; }
        public int group { get; set; }
    }

    class Program
    {
        private void LinqTest()
        {
            Test0 test011 = new Test0 { Names = new String[] { "one", "two", "three" } };
            Test0 test012 = new Test0 { Names = new String[] { "three", "four" } };
            Test0 test013 = new Test0 { Names = new String[] { "ten", "one" } };
            Test1[] test1 = new Test1[] {new Test1 { Tests = new Test0[] { test011, test012, test013 } } };

            // Some magic LINQ to give me 
            // one, two, three, four, ten
            // from test1
            //
            // THE FOLLOWING DOESN'T WORKa
            var allTest1s = (
                                from y
                                    in (from x
                                           in test1
                                         select x.Tests
                                       )
                                select y.Names
                            ).ToArray<String>().Distinct<String>();
        }

        static void Main(string[] args)
        {
            Program program = new Program();
            program.LinqTest();
        }
    }
}

Open in new window

0
Comment
Question by:John Bolter
  • 4
  • 3
  • 3
10 Comments
 
LVL 22

Expert Comment

by:p_davis
ID: 40360285
what is the error/errors you are getting, when compiling.... seems x.Tests should be casted??
0
 

Author Comment

by:John Bolter
ID: 40360297
Hi, I struggled with that too.

I tried

            var allTest1s = (
                                from y
                                    in (from x
                                           in test1
                                         select ((Test0[])x.Tests)
                                       )
                                select y
                            ).ToArray<Test0>().Distinct<String>();

Open in new window


but then I couldn't convert all the Test0's to their Names Strings so I'm sort of missing an inner loop or something.
0
 
LVL 22

Expert Comment

by:p_davis
ID: 40360312
what errors are you getting?
0
 

Author Comment

by:John Bolter
ID: 40360326
The error is it doesn't compile. This is what I think my LINQ query should look like but it is clearly wrong.

The compile error is

Error	1	Instance argument: cannot convert from 'System.Collections.Generic.IEnumerable<ConsoleApplication41.Test0[]>' to 'System.Collections.Generic.IEnumerable<ConsoleApplication41.Test0>'	c:\users\johneb\documents\visual studio 2013\Projects\ConsoleApplication41\ConsoleApplication41\Program.cs	39	30	ConsoleApplication41
Error	2	'System.Collections.Generic.IEnumerable<ConsoleApplication41.Test0[]>' does not contain a definition for 'ToArray' and the best extension method overload 'System.Linq.Enumerable.ToArray<TSource>(System.Collections.Generic.IEnumerable<TSource>)' has some invalid arguments	c:\users\johneb\documents\visual studio 2013\Projects\ConsoleApplication41\ConsoleApplication41\Program.cs	39	30	ConsoleApplication41

Open in new window

0
 
LVL 22

Expert Comment

by:p_davis
ID: 40360329
what happens if, in the select, you get rid of the cast (Test0[])
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 

Author Comment

by:John Bolter
ID: 40360338
It still doesn't compile. I only added the cast because you suggested it above.

Try it. The whole program can be copy/pasted into Visual Studio
0
 
LVL 32

Accepted Solution

by:
it_saige earned 500 total points
ID: 40360355
I think this is what you are after:
			var allTest1s = (from testGroup in test1
						  from test in testGroup.Tests
						  from name in test.Names
						  select name).Distinct();

Open in new window


-saige-
0
 
LVL 32

Expert Comment

by:it_saige
ID: 40360359
Using:
using System;
using System.Linq;

namespace LinqExample
{
	class Test0
	{
		public string[] Names { get; set; }
		public int Id { get; set; }
	}

	class Test1
	{
		public Test0[] Tests { get; set; }
		public int Group { get; set; }
	}

	class Program
	{
		static void Main(string[] args)
		{
			Test0 test011 = new Test0() { Names = new string[] { "one", "two", "three" } };
			Test0 test012 = new Test0() { Names = new string[] { "three", "four" } };
			Test0 test013 = new Test0() { Names = new string[] { "ten", "one" } };
			Test1[] test1 = new Test1[] { new Test1() { Tests = new Test0[] { test011, test012, test013 } } };

			var allTest1s = (from testGroup in test1
						  from test in testGroup.Tests
						  from name in test.Names
						  select name).Distinct();

			foreach (var test in allTest1s)
				Console.WriteLine(test);
			Console.ReadLine();
		}
	}
}

Open in new window

Produces the following output:Capture.JPG
-saige-
0
 

Author Closing Comment

by:John Bolter
ID: 40360361
I see how you've done it now, I didn't realise you could have two "from" like that. I was thinking in a sort of SQL way where that isn't a valid syntax.
Thank you
0
 
LVL 32

Expert Comment

by:it_saige
ID: 40360370
When you really think about it it makes sense.

test1 represents an array of Test1, so you enumerate over each Test1.
Inside of each Test1 you have an array of Test0's, represented as Tests, so you have to enumerate over each Test0.
Then inside of each Test0, you have an array of strings, represented as Names, so you have to enumerate over each Name.

-saige-
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
Composite queries are used to retrieve the results from joining multiple queries after applying any filters. UNION, INTERSECT, MINUS, and UNION ALL are some of the operators used to get certain desired results.​
This video discusses moving either the default database or any database to a new volume.
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now