Okay I might overthink something here.
I try to sort a List by another List. Which works fine as long as another List contains all elements of List.
What would be a good apprach, if another List is incomplete and I'd like to keep the remaining elements at the end of List?
here an example:
public class Column
{
public int Id;
public string Name;
public string Something;
//...
}
public class Columns : IEnumerable<Column>
{
private List<Column> columnList = new List<Column>;
public void SortByName(List<Column> sortedIncompleteList)
{
var sorted = from incomplete in sortedIncompleteList
join current in columnList
on incomplete.FieldName equals current.FieldName
select current;
columnList = sorted.ToList();
}
//...
}
Maybe i am oversimplifying it, but why don't you use OrderBy if you want to sort? You can use following logic to get the items first which are in both collection:
public void SortByName(List<Column> sortedIncompleteList)
{
columnList = columnList
.OrderByDescending(c => sortedIncompleteList.Any(c2 => c.FieldName == c2.FieldName))
.ToList();
}
Update according to the comment: "but not in the order they actually appear in sortedIncompleteList":
public void SortByName(List<Column> sortedIncompleteList)
{
columnList = columnList
.OrderBy(c => {
int index = sortedIncompleteList.FindIndex(c2 => c.FieldName == c2.FieldName);
if (index == -1) return int.MaxValue;
return index;
})
.ToList();
}
I assume the elements in your lists are unique, since Column has an Id field, because my solution will remove duplicates.
public class Columns : IEnumerable<Column>
{
private List<Column> columnList = new List<Column>;
public void SortByName(List<Column> sortedIncompleteList)
{
columnList = sortedIncompleteList.Intersect(columnList)
.Concat(columnList.Except(sortedIncompleteList)).ToList();
}
//...
}
Intersect(), Concat() and Except() will preserve ordering...
You could use something like this:
var ids = sortedIncompleteList.Select(li => li.Id).ToList();
var ordered = from element in columnList
let index = ids.IndexOf(element.Id)
orderby index < 0 ? columnList.Count : index
select element;
Related
I have a list of objects ListA with property Id and I have to make a query in a table that has a column Id and find the rows that the ids are the same. How exactly can I achieve that with a single query and not a foreach loop of listA?
Thank you for your time
foreach(var object in listA)
{
context.Table.Where(x => x.id == object.Id)....
}
Looks like you want to return all rows from the table that have an ID contained in the list of objects with the same ID. The following will achieve this. I can modify my answer to suit your need. Just let me know if you are looking for something slightly different.
void Main()
{
var listA = new List<A> { new A { Id = 1 }, new A { Id = 4 } };
var results = context.Table
.Where(t => listA.Select(l => l.Id).Contains(t.Id))
}
public class A
{
public int Id { get; set; }
}
Here is my service method:
public List<RelatedInvoiceData> GetRelatedInvoices(InvoiceSearch invoiceSearchFilters)
{
List<InvoiceInfoView> invoices = _wiseStepDbContext.InvoiceInfoView.Where(i => i.RecruiterCompanyId == _securityManager.CurrentRecruiterCompanyId).ToList();
List<RelatedInvoiceData> relatedInvoiceViewCollection = GetRelatedInvoiceCollection(invoices);
if (invoiceSearchFilters.CustomerId > 0)
{
relatedInvoiceViewCollection = relatedInvoiceViewCollection.Where(i => i.CustomerId == invoiceSearchFilters.CustomerId).ToList();
}
if (invoiceSearchFilters.VendorId > 0)
{
relatedInvoiceViewCollection = relatedInvoiceViewCollection.Where(i => i.VendorId == invoiceSearchFilters.VendorId).ToList();
}
return relatedInvoiceViewCollection;
}
here is my filterObject :
public class InvoiceSearch
{
public int[] CustomerId { get; set; }
public int[] VendorId { get; set; }
}
Previously I used where in linq for single customer Id now i want filter with multiple customerIds and multiple VendorIds.
Now I want to go with array of CustomerIds. How to write LINQ for Array in Where clause. Thanks for any help
If I understand correctly, you mean that i.CustomerId is now an array or List<>. If that's the case, then you can use the.Contains() method. Something like this should do what you want: relatedInvoiceViewCollection = relatedInvoiceViewCollection.Where(i => i.CustomerId.Contains(invoiceSearchFilters.CustomerId)).ToList();
Edit: This question may be helpful if you want to check for intersections in two arrays, which you can do in your case like this:relatedInvoiceViewCollection = relatedInvoiceViewCollection.Where(i => i.CustomerId.Intersect(invoiceSearchFilters.CustomerId).Any()).ToList();
relatedInvoiceViewCollection.Where(x => relatedInvoiceViewCollection.Contains(invoiceSearchFilters.CustomerId)).ToList();
or
relatedInvoiceViewCollection.Where(x => x.Contains(invoiceSearchFilters.CustomerId)).ToList();
I have a class:
Class A
{
List<double> count;
List<Parts> parts;
}
where the count and parts coincide (meaning count[i] corresponds to parts[i], and so on).
When I sort my count from smallest to biggest using:
count.Sort();
How do I go about rearranging my parts List such that count[i] still corresponds to parts[i]?
It would be easier to wrap those to in a seperate class for this. If every Part has a count then do something like this:
class PartWrapper
{
public Parts parts { get; set; }
public double count { get; set; }
}
If you now want to order ir by anything, you could just take your List<PartWrapper> and do something like this:
var parts = new List<PartWrapper>() { /* store data in it */ };
parts = parts.OrderBy(x => x.count).ToList();
I'd rather implement a class
public class PartCount: IComparable<PartCount> {
public Parts Parts { get; set; }
public Double Count { get; set; }
...
public Boolean CompareTo(PartCount other) {
if (Object.RefeenceEquals(null, other))
return 1;
return Count.CompareTo(other.Count);
}
}
You initial class will be changed into
Class A {
List<PartCount> parts;
}
And you can sort as you want:
// Just sorting, no Linq
parts.Sort();
If you had to keep them as two separate lists, you could use IEnumerable.Zip to associate the two and then sort:
var items = new A()
// populate A
...
var sorted = items.parts.Zip(items.count, Tuple.Create)
.OrderBy(x => x.Item2)
.ToList();
items.count = sorted.Select(x => x.Item1).ToList();
items.parts = sorted.Select(x => x.Item2).ToList();
Using Linq:
class A
{
List<double> count;
List<Parts> parts;
void Sort() {
var result = from item1 in count.Select ((value, index) => new {value, index})
from item2 in parts.Select ((value, index) => new {value, index})
where item1.index == item2.index
orderby item1.value
select new {Count = item1.value, Part = item2.value};
int i = 0;
foreach (var x in result) {
count [i] = x.Count;
parts [i] = x.Part;
i++;
}
}
}
But this is not best way)
To make this easier you can put count also as a property in Parts class.Then you can sort a list of parts like
parts.sort((p1, p2) => p1.count > p2.count)
or
parts.OrderBy(p => p.count)
I'm trying to exclude search results that have a field that stores the ID of an item is empty. This field, for example, is called 'type'. I haven't been able to do this using LINQ. Here is my code example.
public class SearchItem : SearchResultItem
{
[IndexField("type")]
public string Type{ get; set; }
}
public class Search
{
public static IEnumberable<Item> GetItems()
{
List<Item> items = new List<Item>();
var index = ContentSearchManager.GetIndex(new SitecoreIndexableItem(Sitecore.Context.Item));
using (var context = index.CreateSearchContext())
{
var indexItems = context.GetQueryable<SearchResultItem>()
.Where(x => !string.IsNullOrEmpty(x.Type))
.OrderByDescending(x => x.ReleaseDate);
foreach(var indexItem in indexItems)
{
var tempItem = indexItem.GetItem();
items.Add(tempItem);
}
}
return items;
}
}
The empty string comparison isn't working and it the items collection contains items that have empty strings for Type field. I'm using out of the box settings for Lucene.
Also, please poke holes in my code if you see something not right. THis is my first time with Sitecore 7 Search.
Not sure if the string.IsnullOrEmpty is supported by Sitecore Linq, try var indexItems = context.GetQueryable()
.Where(x => x.Type != null)
.OrderByDescending(x => x.ReleaseDate);
Sitecore and Lucene do not support empty strings since an empty field is not in the index. There is no document in the index for an empty item. This post might help you in using Range queries.
Sitecore + Lucene Search FieldQuery with and empty string
Please check with any index viewer tool like Luke and confirm that the index filed type is created or not and if getting created then it is storing the expected value or not.
Try checking by calling function so that you can debug your query.
protected bool checkType(SearchResultItem Ritem)
{
if (Ritem.type != null || !string.IsNullOrEmpty(Ritem.type))
{
return true;
}
return false;
}
Can you try changing the where condition to
public class SearchItem : SearchResultItem
{
[IndexField("type")]
public string Type{ get; set; }
}
public class Search
{
public static IEnumberable<Item> GetItems()
{
List<Item> items = new List<Item>();
var index = ContentSearchManager.GetIndex(new SitecoreIndexableItem(Sitecore.Context.Item));
using (var context = index.CreateSearchContext())
{
var indexItems = context.GetQueryable<FRBSearchResultItem>()
.Where(x => !string.IsNullOrEmpty(x["type"]))
.OrderByDescending(x => x.ReleaseDate);
foreach(var indexItem in indexItems)
{
var tempItem = indexItem.GetItem();
items.Add(tempItem);
}
}
return items;
}
}
It might be too late for the answer but might help future readers with the same problem.
I am using predicate builder as follows,
faqPredicate = faqPredicate.And(x => x.FAQAudience != null);
This results in below error
Message: Comparison of null values is not supported.
Source: Sitecore.ContentSearch.Linq.Lucene
So to fix it while indexing instead of return string.Empty i used return "null";
and in the predicate i checked,
faqPredicate = faqPredicate.And(x => x.FAQAudience != "null");
Yes, it's a workaround but it works. I also tried a comparison with string.Empty but that didn't worked
I'm trying to find all the duplicates in my ObservableCollection, using Lambda/LINQ
Say I have my ObservableCollection<Student> studentList
Each Student has fields
Name
Age
Class
Now in the list, say the following is input in the list
studentList.Add(new Student()
{
Name = Name,
Age= Age,
Class = Class
});
Each time the user enters the data and clicks the button, the data is added. So in my list I would have (as an example)
Bob, 6, Blue Class
Jerry 8, Red Class
Andy 7, Red Class
Bob, 10, Red Class
I would like to loop through the list and find out which names are duplicates
So far my code is:
bool cont = false;
foreach (var dup in studentList)
{
if (!studentList.Any(x => x.Name== dup.Name))
{
cont = true;
}
else
{
cont = false;
break;
}
}
But something is not right. It will always "Bob" in the if statement.
And if I entered 4 completley different names, it would still say false. It takes the last entered value and always compares it to that one, never actually checking them all.
It is a bit hard to explain. If I knew where the problem lie, I would be of more help.
All I would like is to loop through my list to find matching values, and to set the bool to false and break the loop, so that the user can be notified and can make changes before they continue. And I would like the solution to be in a Lambda/LINQ statement
studentList.GroupBy(n => n.Name).Where(n => n.Count() > 1).Select(n => n.Key);
Explaination: This code first groups them by names creating a dictionary in form name => list of students with that name, then checks where there are more than one name and selects that names.
How about this:
bool anyDuplicates = studentList.Select(i => i.Name).Distinct().Count()
< studentList.Count();
This checks if the Distinct list of names is smaller than the full list of students.
According to your comment you don't need a foreach loop you can do this in one line:
bool control = studentList
.Any(s => studentList.Count(x => x.Name == s.Name) > 1);
EDIT
You can simply use the linq like below:
var duplicateNamesList = studentList.GroupBy(x => x.Name).Where(x => x.Count() > 1).Select(x => x.Key);
You have to implement IEqualityComparer<T> for your Student class like below:
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string Class { get; set; }
public class EqualityComparer : IEqualityComparer<Student>
{
public bool Equals(Student x, Student y)
{
return x.Name == y.Name;
}
public int GetHashCode(Student obj)
{
unchecked // overflow is fine
{
int hash = 17;
hash = hash * 23 + obj.Name.GetHashCode();
return hash;
}
}
}
}
Then just invoke studentList.Distinct(new Student.EqualityComparer()) and assign it back to studentList like below:
studentList = studentList.Distinct(new Student.EqualityComparer()).ToList();