I am trying to select a few columns from a single row using LINQ to Entities and then split each column into its own point of an array.
I have the LINQ query getting the results I want, but I can't figure out how to split it into the array. I thought using .ToArray() would work but it doesn't split them.
var LinkData = db.Sections
.Where(s => s.ID == SectionID)
.Select(s => new
{
s.Type,
s.Route
}).ToArray();
How can I split the results from the query so I have a single array of two elements: one for Type and one for Route?
Your Select-statement already creates a list of two-value-items which are stored in instances of anonymous type. So there is no need to create a new two-dimensional array for this. Your linkdata already contains the data you want, however if you´re after one specific combination of (Type, Route) simply call linkedData[myIndex].Route or linkedData[myIndex].Type respectively.
EDIT: If you really want arrays then the following should work:
var arr = linkedData.Select(x => new[] { x.Rote, x.Type }).ToArray();
Which will give you an array of arrays where every element itself contains an array of two elements.
var section = db.Sections
.Where(s => s.ID == SectionID)
.Select(s => new
{
s.Type,
s.Route
})
.SingleOrDefault();
var LinkData = new [] {section.Type, section.Route};
Use a List<> instead
Thats what i would do.
Create a public class of Link Data so:
public class LinkData
{
public string type {get; set;}
public string Route {get;set;}
}
Then in your code
create a List of the Link Data:
List<LinkData> LinkDataList = new List<LinkData>();
then create an object
LinkData obj = new LinkData
add stuff to the object
obj.type = db.Section.Where(s => s.ID==SectionID).Select s=> s.Type new s.Type).SingleOrDefault();
obj.Route = db.Section.Where(s => s.ID==SectionID).Select s=> s.Route new s.Type).SingleOrDefault();;
LinkDataList.Add(obj)
This should give you a clear indication of whats what :)
Related
I'm trying to extract some Lists of strings into a single List.
First I have this class
public class Client
{
public string Name { get; set; }
public List<string> ApiScopes { get; set; }
}
Thus I'm getting my response as a List<Client> and my intention is to take all Client's Scopes into a single List without Looping
I've tried this by LINQ:
var x = clients.Select(c=> c.AllowedScopes.Select(x => x).ToList()).ToList();
this returns a List<List<string>>, and I just want to get all this into one Distinct list of strings.
It sounds like you want SelectMany (which flattens a sequence of sequences into a single sequence), with Distinct as well if you need a list with each scope only appearing once even if it's present for multiple clients:
var scopes = clients.SelectMany(c => c.ApiScopes).Distinct().ToList();
This assumes that Client.ApiScopes is never null. If it might be null, you need a little bit more work:
var scopes = clients
.SelectMany(c => ((IEnumerable<string>) c.ApiScopes) ?? Enumerable.Empty<string>())
.Distinct()
.ToList();
You can use SelectMany to flatten results :
var scopes=clients.SelectMany(client=>client.ApiScopes)
.Distinct()
.ToList();
This is equivalent to :
var scopes= ( from client in clients
from scope in client.ApiScopes
select scope
)
.Distinct()
.ToList();
Let's say I have the following:
public class Person
{
public string Name{get;set;}
public string Other{get;set;}
public string Other2{get;set;}
public int? Sequence{get;set;}
}
new Person("bob","other1","other2",1)
new Person("bob","other1","other2",2)
new Person("bob","other1","other2",3)
new Person("bob","other1","other2",4)
new Person("Alice","other1","other2")
new Person("Alice","other1","other2",1)
new Person("Alan","other1","other2",1)
new Person("Alan","other1","other2",2)
new Person("Alan","other1","other2",3)
new Person("Alex","other1","other2")
new Person("Alex","other1","other2",1)
new Person("Alex","other1","other2",2)
As shown some of the objects have sequence 1-n and some don't.
Could I use LINQ to pull objects by sequence from the given list?
Desired output would be:
Bob and all his related data where a sequence is there like 1,2,3,4 records
Alex 2 records as he only has sequences 1 and 2.
So the output would be another object by name and data by sequence.
new {Name="Bob", Data=new[]{
Other = "other"
Sequence = 1
Other2 = "Other2" //etc
}}
The sequence will always increment by 1 and be in order, but how many there might be is unknown.
If I have not made something clear just ask.
What I tried
I tried without using LINQ and looping through the list and processing each object and passing out a newly created object for each row using lots of if's.
I am just wondering if there is an easier way with LINQ although my way works it's ugly.
If I understand correctly:
var result = yourCollection
.Where(x => x.Sequence.HasValue)
.GroupBy(x => x.Name)
.Select(grp => new
{
Name = grp.Key,
Data = grp.Select(x => new
{
x.Other,
x.Sequence,
x.Other2
})
});
This assumes the list is already ordered by Sequence; if not, just add an .OrderBy(x => x.Sequence.Value) before the GroupBy.
Hi I have List of strings as below.
List<string> MyList = new List<string> { "[FirstName]", "[LastName]", "[VoicePhoneNumber]", "[SMSPhoneNumber]" };
I need to get all the elements from the List if exist in string in order. For example my string is
string MessageContent = Hello [LastName] [FirstName]There, this message is for [SMSPhoneNumber]
Right now I am doing
var Exists = MyList.Where(MessageContent.Contains);
This new list have all the items from MyList which occured in MessageContent string but not in order.
How i can get occurrence in order in string?
Desired List as per example is = { "[LastName]","[FirstName]","[SMSPhoneNumber]" }
I would suggest using IndexOf to determine position (and thereby order) as well as existence to avoid searching MessageContent twice at the expense of sorting the answer:
var ans = MyList.Select(w => new { w, pos = MessageContent.IndexOf(w) })
.Where(wp => wp.pos >= 0)
.OrderBy(wp => wp.pos)
.Select(wp => wp.w)
.ToList();
However, if a field may appear more than once, or if you think avoiding the repeated scanning of MessageContent is faster than multiple IndexOf (once per MyList member) (probably not) and avoiding the sort, then you can invert the search (using Span to avoid generating lots of Strings):
var ans2 = Enumerable.Range(0, MessageContent.Length-MyList.Select(w => w.Length).Min())
.Select(p => MyList.FirstOrDefault(w => MessageContent.AsSpan().Slice(p).StartsWith(w)))
.Where(w => w != null)
.ToList();
I did it Using
var Exists = MyList.Where(MessageContent.Contains).OrderBy(s => MessageContent.IndexOf(s));
I have a List of Vehicles with various fields such as registration, age, engine size, etc. One of these fields is a "tag" field which in itself is a List of tags.
I am trying to filter this list of vehicles to only show the ones which include a tag which matches a value in a separate neededTags list.
I am trying to do this using Linq and Lambda expressions.
I have managed to get this working in situations where the Tag field in the main List is just a normal string field, NOT a list of strings. The code for this is here:
filteredVehicles = Vehicles.Where(x => neededTags.Any(y => y == x.tags)).ToList();
where neededTags is my list of tags that I am interested in.
My problem now is that if the Tag element in the vehicles list is actually a list of tags then the compare element above says "Operator '==' cannot be applied to operands of type 'string' and 'List'"
I think I need to compare every element in the Vehicles Tag list with those in the neededTags list, but I just do not know how to do this.
Any assistance is greatly appreciated.
You want to check if the intersection of the vehicle's list of tags and the list of needed tags has any elements (if there is at least on element in vehicle's tags that is also in needed tags):
filteredVehicles = Vehicles.Where(v => v.Tags.Intersect(neededTags).Any()).ToList();
If the vehicle's tag may be null, you can use the null-conditional operator
filteredVehicles = Vehicles.Where(v => v.Tags?.Intersect(neededTags).Any() == true).ToList();
You can't compare a string to a list of strings for equality. Use the .Contains method to check for that:
// this is the short form for: .Where(x => neededTags.Any(y => x.tags.Contains(y)))
filteredVehicles = Vehicles.Where(x => neededTags.Any(x.tags.Contains)).ToList();
I think Rene V has the best answer, but this also works and I've see it done this way in other posts. You can just use the Any method on both lists. I added test data also.
filteredVehicles = Vehicles.Where(v => (v.tags ?? new List<string>()).Any(t => neededTags.Any(n => n == t))).ToList();
Test Code:
var neededTags = new List<string> { "tag1", "tag2" };
var Vehicles = new[] {
new {name = "vehicle1", tags = new List<string> { "tag1" } },
new {name = "vehicle2", tags = new List<string> { "tag5" } }
}.ToList();
var filteredVehicles = Vehicles.Where(v => (v.tags ?? new List<string>()).Any(t => neededTags.Any(n => n == t))).ToList();
I got 5 lists. One is containing the date of release and the others are the attributes of that list but seperated in multiple lists.
List<string> sortedDateList = x1.OrderBy(x => x).ToList();
This code is sorting the list with the oldest date first, like it should. But I also want to sort (sync) the other attributes list, because they need the same index as the date.
How can I realize that? I'm new to Linq-methods.
You could use the .Zip() method to combine the lists as described here. You could combine them into a class or an anonymous type and then sort them.
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => new { Num = first, Word = second });
var sorted = numbersAndWords.OrderBy(x => x.Num).ToList();
Alternately, if you can guarantee that all the lists are of the same length (or just grab the shortest list) you could use the following instead of the .Zip() extension.
var numbersAndWords = numbers.Select((number, i) => new { Num = number, Word = words[i], Foo = myFoos[i] }); // Where myFoos is another collection.
And in the lambda combine all the items from the separate lists into an object at the same time by accessing the collection by index. (Avoids multiple use of .Zip()) Of course, if you try to access an index that is larger than the list size you will get an IndexOutOfRangeException.
As far as I understand your question, you have different lists containing properties of certain objects. You should definitely look into storing all data into one list of a class of your making, where you consolidate all separate information into one object:
var list = new List<YourClass>
{
new YourClass
{
Date = ...,
OtherProperty = ...,
},
new YourClass
{
Date = ...,
OtherProperty = ...,
},
};
var ordered = list.OrderBy(o => o.Date);
But if you insist in storing different properties each in their own list, then you could to select the dates with their index, then sort that, as explained in C# Sorting list by another list:
var orderedDates = list.Select((n, index) => new { Date = n, Index = index })
.OrderBy(x => x.Date)
.ToList();
Then you can use the indexes of the sorted objects to look up the properties in the other lists, by index, or sort them on index as explained in C# Sort list while also returning the original index positions?, Sorting a list and figuring out the index, and so on.
It almost sounds like you want 1 list of a class.
public class MyClass{
public string Date{get; set;} //DateTime is a better type to use for dates by the way
public string Value2{get; set;}
public string Value3{get; set;}
public string Value4{get; set;}
public string Value5{get; set;}
}
...
var sortedDateList = x1.OrderBy(x => x.Date).ToList()
Create an Object containing the date and attributes:
public class DateWithAttributes
{
public string Date {get;set;}
public Attribute Attribute1 {get;set;}
public Attribute Attribute2 {get;set;}
...
}
List<DateWithAttributes> DateWithAttributesList = new List<DateWithAttributes>()
{
DateWithAttribute1,
DateWithAttribute2
}
List<DateWithAttributes> sortedDateList = DateWithAttributesList.OrderBy(x => x.date).ToList();
If you want to keep the lists separate, and/or create the ordered versions as separate lists, then you can concatenate the index to the dates and sort by dates, then use the sorted indexes:
var orderedIndexedDateOfReleases = dateOfReleases.Select((d, i) => new { d, i }).OrderBy(di => di.d);
var orderedDateOfReleases = orderedIndexedDateOfReleases.Select(di => di.d).ToList();
var orderedMovieNames = orderedIndexedDateOfReleases.Select(di => movieNames[di.i]).ToList();
If you don't mind the result being combined, you can create a class or use an anonymous class, and again sort by the dates:
var orderedTogether = dateOfReleases.Select((d, i) => new { dateOfRelease = d, movieName = movieNames[i] }).OrderBy(g => g.dateOfRelease).ToList();