Is it possible to execute a combined Linq query as a some sort of query in c#?
For example I've got 3 methods:
private queueCollection;
private void testA(parameterA)
{
if(parameterA != null)
{
queueCollection.Add(someCollection.Where(a => a.Name = parameterA))
}
else
{
queueCollection.Add(someCollection);
}
}
private void testB(parameterB)
{
if(parameterB != null)
{
queueCollection.Add(someCollection.Where(b => b.Name = parameterB))
}
else
{
queueCollection.Add(someCollection);
}
}
private void testC(parameterC)
{
if(parameterC != null)
{
queueCollection.Add(someCollection.Where(c => c.Name = parameterC))
}
else
{
queueCollection.Add(someCollection);
}
}
public void linqQueue()
{
start queueCollection;
}
So can I query different combination at once and don't need to code every combination separately?
I want to create a sorting filter on the collection so if I'll get parameter A, I will get A results from collection; if I add B, I want A and B, and if I get A null I want B only etc.
As I understand your question correctly, the answer is Yes, you can. You can use Predicates in Linq queries.
private void test(parameterA,parameterB,parameterC)
{
queueCollection.Add(someCollection.Where(a => (parameterA != null && a.Name = parameterA) && (parameterB != null && a.Name = parameterB) && (parameterC != null && a.Name = parameterC)));
}
or if you need OR operator
private void test(parameterA,parameterB,parameterC)
{
queueCollection.Add(someCollection.Where(a => (parameterA != null && a.Name = parameterA) || (parameterB != null && a.Name = parameterB) || (parameterC != null && a.Name = parameterC)));
}
Related
I have an observable collection.
The class of this collection has several fields which in turn can have server values.
I wish my user to be able to search on numerous fields and values.
I have got as far as using an ICollection but all the examples I have seen is based on searching on 1 field.
This is my class:
public class Tasks
{
private string JobPriority;
private string JobLabel;
private string JobType;
private string UserRef;
}
JobPriority can be 'High', 'Low'
JobLabel can be 'Apple', 'Android', 'Microsoft'
JobType can be 'Internal', 'Private', 'Public'
So, I instantiate my collection as such:
public ObservableCollection<KanbanModelExtra> Tasks
{
get
{
if (_tasks == null)
{
TaskView = CollectionViewSource.GetDefaultView(_tasks);
TaskView.Filter = TaskFilter;
}
return _tasks;
}
set
{
_tasks = value;
}
}
public ICollectionView TaskView { get; private set; }
and set my filter as such:
private bool TaskFilter(
object item )
{
var task = item as KanbanModelExtra;
if ( task == null )
{
return false;
}
foreach ( var searchItem1 in JobPrioritiesToSearchOn )
{
if ( task.JobPriority == searchItem1 )
{
foreach ( var searchItem2 in JobLabelsToSearchOn )
{
if ( task.JobLabel == searchItem2)
{
foreach (var searchItem3 in JobTypesToSearchOn)
{
if (task.JobType == searchItem3)
{
if ( SearchByCurrentUser )
{
if ( task.UserRef == HeartBeat.CurrentUser.UserRef )
{
return true;
}
}
else
{
return true;
}
}
}
}
}
}
}
return false;
}
but this seems 'heavy' and ugly. Also, every change will refresh the collection. Where as I would lie to fresh the collection after all criteria has been choosen.
Is there a better way?
Chain the tests together.
var result = JobPrioritiesToSearchOn.Any(x => x == task.JobPriority);
result = result && JobLabelsToSearchOn.Any(x => x == task.JobLabel);
result = result && JobTypesToSearchOn.Any(x => x == task.JobType);
if (SearchByCurrentUser)
{
result = result && task.UserRef == HeartBeat.CurrentUser.UserRef;
}
return result;
Any() will return true if any of the collection match the filter passed in. In plain English, the first line evaluates to true if any of the JobPrioritiesToSearchOn items are equal to task.JobPriority.
foreach madness can be replaced by this expression:
return ((SearchByCurrentUser && task.UserRef == HeartBeat.CurrentUser.UserRef) || !SearchByCurrentUser) &&
JobPrioritiesToSearchOn.Contains(task.JobPriority) &&
JobLabelsToSearchOn.Contains(task.JobLabel) &&
JobTypesToSearchOn.Contains(task.JobType));
I want an alphabetic sort with one exception.
There is a Group with a Name = "Public" and an ID = "0" that I want first.
(would rather use ID = 0)
After that then sort the rest by Name.
This does not return public first.
public IEnumerable<GroupAuthority> GroupAuthoritysSorted
{
get
{
return GroupAuthoritys.OrderBy(x => x.Group.Name);
}
}
What I want is:
return GroupAuthoritys.Where(x => x.ID == 0)
UNION
GroupAuthoritys.Where(x => x.ID > 0).OrderBy(x => x.Group.Name);
GroupAuthority has a public property Group and Group has Public properties ID and Name.
I used basically the accepted answer
using System.ComponentModel;
namespace SortCustom
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TestSort();
}
private void TestSort()
{
List<CustomSort> LCS = new List<CustomSort>();
LCS.Add(new CustomSort(5, "sss"));
LCS.Add(new CustomSort(6, "xxx"));
LCS.Add(new CustomSort(4, "xxx"));
LCS.Add(new CustomSort(3, "aaa"));
LCS.Add(new CustomSort(7, "bbb"));
LCS.Add(new CustomSort(0, "pub"));
LCS.Add(new CustomSort(2, "eee"));
LCS.Add(new CustomSort(3, "www"));
foreach (CustomSort cs in LCS) System.Diagnostics.Debug.WriteLine(cs.Name);
LCS.Sort();
foreach (CustomSort cs in LCS) System.Diagnostics.Debug.WriteLine(cs.Name);
}
}
public class CustomSort : Object, INotifyPropertyChanged, IComparable<CustomSort>
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null) PropertyChanged(this, e);
}
private Int16 id;
private string name;
public Int16 ID { get { return id; } }
public String Name { get { return name; } }
public int CompareTo(CustomSort obj)
{
if (this.ID == 0) return -1;
if (obj == null) return 1;
if (obj is CustomSort)
{
CustomSort comp = (CustomSort)obj;
if (comp.ID == 0) return 1;
return string.Compare(this.Name, comp.Name, true);
}
else
{
return 1;
}
}
public override bool Equals(Object obj)
{
// Check for null values and compare run-time types.
if (obj == null) return false;
if (!(obj is CustomSort)) return false;
CustomSort comp = (CustomSort)obj;
return (comp.ID == this.ID);
}
public override int GetHashCode()
{
return (Int32)ID;
}
public CustomSort(Int16 ID, String Name)
{
id = ID;
name = Name;
}
}
}
You need to use a comparison function, they are functions that from two instances of your type return an integer that return 0 if both are equals, a negative value if the first is less than the second and a positive value if the first is greater than the second.
MSDN has a nice table that is easier to follow than text (StackOverflow still doesn't support tables in 2014)
IComparer<T>
Most sort methods accept a custom comparer implementation of type IComparer<T> you should create one encapsulating your custom rules for Group :
class GroupComparer : IComparer<Group>
{
public int Compare(Group a, Group b)
{
if (a != null && b != null && (a.Id == 0 || b.Id == 0))
{
if (a.Id == b.Id)
{
// Mandatory as some sort algorithms require Compare(a, b) and Compare(b, a) to be consistent
return 0;
}
return a.Id == 0 ? -1 : 1;
}
if (a == null || b == null)
{
if (ReferenceEquals(a, b))
{
return 0;
}
return a == null ? -1 : 1;
}
return Comparer<string>.Default.Compare(a.Name, b.Name);
}
}
Usage:
items.OrderBy(_ => _, new GroupAuthorityComparer());
IComparable<T>
If it is the only way to compare Group instances you should make it implement IComparable<T> so that no aditional code is needed if anyone want to sort your class :
class Group : IComparable<Group>
{
...
public int CompareTo(Group b)
{
if (b != null && (Id == 0 || b.Id == 0))
{
if (Id == b.Id)
{
// Mandatory as some sort algorithms require Compare(a, b) and Compare(b, a) to be consistent
return 0;
}
return Id == 0 ? -1 : 1;
}
return Comparer<string>.Default.Compare(Name, b.Name);
}
}
Usage:
items.OrderBy(_ => _.Group);
The choice between one way or the other should be done depending on where this specific comparer is used: Is it the main ordering for this type of item or just the ordering that should be used in one specific case, for example only in some administrative view.
You can even go one level up and provide an IComparable<GroupAuthority> implementation (It's easy once Group implement IComparable<Group>):
class GroupAuthority : IComparable<GroupAuthority>
{
...
public int CompareTo(GroupAuthority b)
{
return Comparer<Group>.Default.Compare(Group, b.Group);
}
}
Usage:
items.OrderBy(_ => _);
The advantage of the last one is that it will be used automatically, so code like: GroupAuthoritys.ToList().Sort() will do the correct thing out of the box.
You can try something like this
list.Sort((x, y) =>
{
if (x.Id == 0)
{
return -1;
}
if (y.Id == 0)
{
return 1;
}
return x.Group.Name.CompareTo(y.Group.Name);
});
Where list is List<T>.
This method takes advantage of custom sort option provided by List<T> using Comparison<T> delegate.
Basically what this method does is, it just adds special condition for comparison when Id, If it is zero it will return a value indicating the object is smaller which makes the object to come in top of the list. If not, it sorts the object using its Group.Name property in ascending order.
public IEnumerable<GroupAuthority> GroupAuthoritysSorted
{
get
{
return GroupAuthoritys.OrderBy(x => x.Group.ID == 0)
.ThenBy(x => x.Group.Name);
}
}
I am having trouble understating if this is a basic feature on omu.valueinjecter.
I have 2 identical Classes (difference is basically namespaces) and the Source class has public fields instead of public properties.
Is it possible to make ValueInjecter map the public fields?
Thanks
For those of you who are after a copy-paste solution:
public class PropertyAndFieldInjection : ValueInjection
{
protected string[] ignoredProps;
public PropertyAndFieldInjection()
{
}
public PropertyAndFieldInjection(string[] ignoredProps)
{
this.ignoredProps = ignoredProps;
}
protected override void Inject(object source, object target)
{
var sourceProps = source.GetType().GetProps();
foreach (var sourceProp in sourceProps)
{
Execute(sourceProp, source, target);
}
var sourceFields = source.GetType().GetFields();
foreach (var sourceField in sourceFields)
{
Execute(sourceField, source, target);
}
}
protected virtual void Execute(PropertyInfo sp, object source, object target)
{
if (!sp.CanRead || sp.GetGetMethod() == null || (ignoredProps != null && ignoredProps.Contains(sp.Name)))
return;
var tp = target.GetType().GetProperty(sp.Name);
if (tp != null && tp.CanWrite && tp.PropertyType == sp.PropertyType && tp.GetSetMethod() != null)
{
tp.SetValue(target, sp.GetValue(source, null), null);
return;
}
var tf = target.GetType().GetField(sp.Name);
if (tf != null && tf.FieldType == sp.PropertyType)
{
tf.SetValue(target, sp.GetValue(source, null));
}
}
protected virtual void Execute(FieldInfo sf, object source, object target)
{
if (ignoredProps != null && ignoredProps.Contains(sf.Name))
return;
var tf = target.GetType().GetField(sf.Name);
if (tf != null && tf.FieldType == sf.FieldType)
{
tf.SetValue(target, sf.GetValue(source));
return;
}
var tp = target.GetType().GetProperty(sf.Name);
if (tp != null && tp.CanWrite && tp.PropertyType == sf.FieldType && tp.GetSetMethod() != null)
{
tp.SetValue(target, sf.GetValue(source), null);
}
}
}
This works in all 4 directions (prop->prop, prop<->field, field->field). I didn't test it thoroughly so use it at your own risk.
This is my linq query and I get lots of duplicates with school names.
so I created a regex function to trim the text:
public static string MyTrimmings(string str)
{
return Regex.Replace(str, #"^\s*$\n", string.Empty, RegexOptions.Multiline).TrimEnd();
}
the text gets trimed alright, however, the dropdown values are all duplicates! please help me eliminate duplicates, oh Linq joy!!
ViewBag.schools = new[]{new SelectListItem
{
Value = "",
Text = "All"
}}.Concat(
db.Schools.Where(x => (x.name != null)).OrderBy(o => o.name).ToList().Select(s => new SelectListItem
{
Value = MyTrimmings(s.name),
Text = MyTrimmings(s.name)
}).Distinct()
);
Distinct is poor, GroupBy for the win:
db.Schools.GroupBy(school => school.name).Select(grp => grp.First());
Assuming you have a School class you can write an IEqualityComparer
class SchoolComparer : IEqualityComparer<School>
{
public bool Equals(School x, School y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the school' properties are equal.
return x.Name == y.Name;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(School school)
{
//Check whether the object is null
if (Object.ReferenceEquals(school, null)) return 0;
//Get hash code for the Name field if it is not null.
int hashSchoolName = school.Name == null ? 0 : school.Name.GetHashCode();
//Calculate the hash code for the school.
return hashSchoolName;
}
}
Then your linq query would look like this:
db.Schools.Where(x => x.name != null)
.OrderBy(o => o.name).ToList()
.Distinct(new SchoolComparer())
.Select(s => new SelectListItem
{
Value = MyTrimmings(s.name),
Text = MyTrimmings(s.name)
});
You could make your class implement the IEquatable<T> interface, so Distinct will know how to compare them. Like this (basic example):
public class SelectListItem : IEquatable<SelectListItem>
{
public string Value { get; set; }
public string Text { get; set; }
public bool Equals(SelectListItem other)
{
if (other == null)
{
return false;
}
return Value == other.Value && Text == other.Text;
}
public override int GetHashCode()
{
unchecked
{
int hash = 17;
if (Value != null)
{
hash = hash * 23 + Value.GetHashCode();
}
if (Text != null)
{
hash = hash * 23 + Text.GetHashCode();
}
return hash;
}
}
}
(GetHashCode taken fron John Skeet's answer here: https://stackoverflow.com/a/263416/249000)
I have this piece of code:
public string Label { get; set; }
public bool IsSpoon(out Spoon sp)
{
sp = null;
foreach (Tool t in Tools.GetAllItems())
if ((sp = t.AllSpoons.FirstOrDefault(x => x.Label == this.Label)) != null)
break;
return sp != null;
}
How can this be optimised via LINQ?
I thought of something like this but this isn't allowed:
public string Label { get; set; }
public bool IsSpoon(out Spoon sp)
{
return Tools.GetAllItems().FirstOrDefault(x => (sp = x.AllSpoons.FirstOrDefault(y => y.Label == this.Label)) != null) != null;
}
EDIT : I did not notice the sp parameter, here is an update:
sp = Tools
.GetAllItems()
.SelectMany(x => x.AllSpoons)
.FirstOrDefault(y => y.Label == this.Label);
return sp != null;
You can flatten the list with SelectMany. Then you don't have to do anything tricky like assigning a value in the middle of a LINQ statement.
public bool IsSpoon(out Spoon sp)
{
sp = Tools.GetAllItems().SelectMany(t => t.AllSpoons)
.FirstOrDefault(x => x.Label == this.Label);
return sp != null;
}
Here is the essentially equivalent query syntax:
sp = (from tool in Tools.GetAllItems()
from spoon in tool.AllSpoons
where spoon.Label == this.Label
select spoon).FirstOrDefault();
public bool IsSpoon(out Spoon sp)
{
return Tools.GetAllItems()
.SelectMany(t => t.AllSpoons)
.Any(x => x.Label == this.Label);
}