I have a line of code:
bool true/false = array1.All(a => array2.Any(t => t.field == a.field));
I do not understand this combination of all + any.
Does it mean 'No field of array1 equals any field of array2' then return true ?
Would this not be the same as array1.Except(array2).Any(); ?
UPDATE
Accidently I put a "!" before the .Any() !!!
I think they are really different, it also depends on how you array is structured. If it has only field property or it has other properties as well.
Code inspection
array1.All(a => array2.Any(t => t.field == a.field));
Return true if For each element in array1 there's at least one element in array2 that has the
same value for the field property
array1.Except(array2).Any();
Return True if there's at least one element of array1 not present in
array2
Now given your context, if field is the only property of your structure it produces the same result, but it does not if there's other things going on.
For example
struct Test
{
public string int { get; set; }
public string int { get; set; }
}
//...
var array1 = new Test[]
{
new Test { Field = 0, OtherField = 1 },
new Test { Field = 1, OtherField = 2 }
}
var array2 = new Test[]
{
new Test { Field = 0, OtherField = 1 },
new Test { Field = 2, OtherField = 2 }
}
First case: is it true that for each element of array1 there's at least one element in array2 with same value in field property? False
Second case: is it true that at least one element of array1 is not present in array2? True
That means return true if there is no item in array2 which has the same value in field for all of items in array1.
Simpler version:
For all items in array1, there is no item in array2 with same value of field.
UPDATE:
Now the modified version is much simpler since it says return true if for all items in array1 there is an item in array2 with same value for field.
In summary, your first solution is to check if all the elements in array1 have the same field value in some element in array2, which could be also translated to:
var areContained =!array1.Select(e=>e.field)).Except(array2.Select(d=>d.field)).Any();
Another variant could be using a hash that could help to the efficiency if the superset if too big:
HashSet<int> hashSet = new HashSet<int>(array2.Select(d=>d.field));//Superset
bool contained = array1.Select(e=>e.field)).All(i => hashSet.Contains(i));
In your alternative you are comparing based on object instances of the arrays by using the default equality comparer, so that can produce a completely different result. Take a look the example in this link
Related
Let's imagine I have a list, all elements have an order property except for Element with Id 4:
List<Element> elements = new List<Element> {
new Element {Id = 1, Name = "First", Order = 2},
new Element {Id = 2, Name = "Second", Order = 3},
new Element {Id = 3, Name = "Third", Order = 1},
new Element {Id = 4, Name = "Fourth", Order = null};
I need to sort elements in-place based on the order property but the element with Id 4 is not taken into consideration as it has order property set to null.
public void ModifyList() {
Order(elements);
return elements; // I want to end up with Element Id:3,
// Element Id:1, Element Id:2 and the last
// one Element with Id:4 (it is returned
// as the last element as the sort did not apply to it.
}
private static void Order(IList<Element> elements) {
elements.Sort((x, y) => x.Order.CompareTo(y.Order));
}
I know that I could first create one list that contains elements that have order property, sort them, and than append to the list which does not have that property, is there a cleaner way to do it. (without using OrderBy()).
You can write your own comparer to ensure that the Nulls go at the end:
public sealed class ElementComparer: IComparer<Element>
{
public int Compare(Element? x, Element? y)
{
if (ReferenceEquals(x, y))
return 0;
if (ReferenceEquals(null, y))
return 1;
if (ReferenceEquals(null, x))
return -1;
if (x.Order == null)
return 1;
if (y.Order == null)
return -1;
return x.Order.Value.CompareTo(y.Order.Value);
}
}
Then you can in-place sort the elements in the list like so:
elements.Sort(new ElementComparer());
If you try it, you'll see that it's ordered by .Order but with any null ones at the end.
One thing to be aware of is that List<T>.Sort() is an unstable sort, which means that after sorting, the order of items with the same .Order (including null ones) is undefined.
Enumerable.OrderBy() performs a stable sort.
Try:
foreach(var item in elements.OrderBy( x=> (x.Order is null ? 9999 : x.Order))) {
System.Console.WriteLine(item.Id);
}
Of course you should change the 9999 when the values of Id are also in that range...
see: fiddle
I am trying to order a list of lists by one of the fields.
I have two lists in one grouped list. The first contains the Id, the second contains the count. I was successfully able to group the list of lists by Id and reformat it.
for (int i = 0; i < GroupedListofLists.Count; i++)
{
tempo_Id.Add(GroupedListofLists[i][0]);
tempo_count.Add(GroupedListofLists[i][1]);
}
GroupedListofLists.Clear();
GroupedListofLists.Add(tempo_Id);
GroupedListofLists.Add(tempo_count);
If I print out the GroupedListofLists I will have distinct Ids (GroupedListofLists[0]) each with their count in the second(GroupedListofLists [1]).
Now when I try to sort this list with lambda expression I have a problem. I tried these two methods:
GroupedlistofLists.Sort( (a, b) => Convert.ToDouble(a[idx]).CompareTo(Convert.ToDouble(b[idx])));
AND
GroupedlistofLists = GroupedlistofLists.OrderBy(x => Convert.ToDouble(x[idx])).ToList();
A problem arises.
In the first method no matter what values I used for the variable 'idx', a will be assigned the values of GroupedListofLists[0] and b the values of GroupedListofLists[1].
In the second, no matter what values I use for the variable 'idx' (0 or 1), x will always contain the values for GroupedListofLists[0]. Which are the Id value and I need to sort them by Count, so GroupedListofLists[1].
I hope I was clear.
Thank you in advance.
I don't exacly know what you're trying to do. But i'll do a guess:
// Build some List you want to sort
List<string> myList = new List<string>() { "3", "1", "2" };
// Sort the List
myList = myList.OrderBy(a => Convert.ToDouble(a));
The Lambda-Expression in OrderBy needs to select a value which will be ordered in default manner. The Lambda-Expression will be run for every item in your list. The results will be used as order-key. you don't need any index.
Sort can be used so sort complex types.
Better version should work on a List with correct class and type. A Convert within a lambda-expression should be avoided!
// Some example-class with multiple properties
public class MyItem
{
public string Name { get; set; }
public double Value { get; set; }
}
// Some test-data
List<MyItem> myList = new List<MyItem>()
{
new MyItem() { Name = "One", Value = 1 },
new MyItem() { Name = "Three", Value = 3 },
new MyItem() { Name = "Two", Value = 2 }
}
// select the value you want to use for ordering the list.
myList = myList.OrderBy(item => item.Value);
// Expected output: 1, 2, 3
foreach(MyItem item in myList)
{
Console.WriteLine(item.Value + ", " + item.Name);
}
// Expected output: 3, 2, 1
myList = myList.OrderBy(item => item.Name);
foreach(MyItem item in myList)
{
Console.WriteLine(item.Value + ", " + item.Name);
}
(I got no Visual Studio installed, so check for typos ;))
So I have
List<string[]> listy = new List<string[]>();
listy.add('a','1','blue');
listy.add('b','2','yellow');
And i want to search through all of the list ti find the index where the array containing 'yellow' is, and return the first element value, in this case 'b'.
Is there a way to do this with built in functions or am i going to need to write my own search here?
Relatively new to c# and not aware of good practice or all the built in functions. Lists and arrays im ok with but lists of arrays baffles me somewhat.
Thanks in advance.
As others have already suggested, the easiest way to do this involves a very powerful C# feature called LINQ ("Language INtegrated Queries). It gives you a SQL-like syntax for querying collections of objects (or databases, or XML documents, or JSON documents).
To make LINQ work, you will need to add this at the top of your source code file:
using System.Linq;
Then you can write:
IEnumerable<string> yellowThings =
from stringArray in listy
where stringArray.Contains("yellow")
select stringArray[0];
Or equivalently:
IEnumerable<string> yellowThings =
listy.Where(strings => strings.Contains("yellow"))
.Select(strings => strings[0]);
At this point, yellowThings is an object containing a description of the query that you want to run. You can write other LINQ queries on top of it if you want, and it won't actually perform the search until you ask to see the results.
You now have several options...
Loop over the yellow things:
foreach(string thing in yellowThings)
{
// do something with thing...
}
(Don't do this more than once, otherwise the query will be evaluated repeatedly.)
Get a list or array :
List<string> listOfYellowThings = yellowThings.ToList();
string[] arrayOfYellowThings = yellowThings.ToArray();
If you expect to have exactly one yellow thing:
string result = yellowThings.Single();
// Will throw an exception if the number of matches is zero or greater than 1
If you expect to have either zero or one yellow things:
string result = yellowThings.SingleOrDefault();
// result will be null if there are no matches.
// An exception will be thrown if there is more than one match.
If you expect to have one or more yellow things, but only want the first one:
string result = yellowThings.First();
// Will throw an exception if there are no yellow things
If you expect to have zero or more yellow things, but only want the first one if it exists:
string result = yellowThings.FirstOrDefault();
// result will be null if there are no yellow things.
Based on the problem explanation provided by you following is the solution I can suggest.
List<string[]> listy = new List<string[]>();
listy.Add(new string[] { "a", "1", "blue"});
listy.Add(new string[] { "b", "2", "yellow"});
var target = listy.FirstOrDefault(item => item.Contains("yellow"));
if (target != null)
{
Console.WriteLine(target[0]);
}
This should solve your issue. Let me know if I am missing any use case here.
You might consider changing the data structure,
Have a class for your data as follows,
public class Myclas
{
public string name { get; set; }
public int id { get; set; }
public string color { get; set; }
}
And then,
static void Main(string[] args)
{
List<Myclas> listy = new List<Myclas>();
listy.Add(new Myclas { name = "a", id = 1, color = "blue" });
listy.Add(new Myclas { name = "b", id = 1, color = "yellow" });
var result = listy.FirstOrDefault(t => t.color == "yellow");
}
Your current situation is
List<string[]> listy = new List<string[]>();
listy.Add(new string[]{"a","1","blue"});
listy.Add(new string[]{"b","2","yellow"});
Now there are Linq methods, so this is what you're trying to do
var result = listy.FirstOrDefault(x => x.Contains("yellow"))?[0];
I have a small list of bytes and I want to test that they're all different values.
For instance, I have this:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
What's the best way to check if all values are distinct or not?
bool isUnique = theList.Distinct().Count() == theList.Count();
Here's another approach which is more efficient than Enumerable.Distinct + Enumerable.Count (all the more if the sequence is not a collection type). It uses a HashSet<T> which eliminates duplicates, is very efficient in lookups and has a count-property:
var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;
or another - more subtle and efficient - approach:
var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);
HashSet<T>.Add returns false if the element could not be added since it was already in the HashSet. Enumerable.All stops on the first "false".
Okay, here is the most efficient method I can think of using standard .Net
using System;
using System.Collections.Generic;
public static class Extension
{
public static bool HasDuplicate<T>(
this IEnumerable<T> source,
out T firstDuplicate)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
var checkBuffer = new HashSet<T>();
foreach (var t in source)
{
if (checkBuffer.Add(t))
{
continue;
}
firstDuplicate = t;
return true;
}
firstDuplicate = default(T);
return false;
}
}
essentially, what is the point of enumerating the whole sequence twice if all you want to do is find the first duplicate.
I could optimise this more by special casing an empty and single element sequences but that would depreciate from readability/maintainability with minimal gain.
The similar logic to Distinct using GroupBy:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
I check if an IEnumerable (aray, list, etc ) is unique like this :
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;
One can also do: Use Hashset
var uniqueIds = new HashSet<long>(originalList.Select(item => item.Id));
if (uniqueIds.Count != originalList.Count)
{
}
There are many solutions.
And no doubt more beautiful ones with the usage of LINQ as "juergen d" and "Tim Schmelter" mentioned.
But, if you bare "Complexity" and speed, the best solution will be to implement it by yourself.
One of the solution will be, to create an array of N size (for byte it's 256).
And loop the array, and on every iteration will test the matching number index if the value is 1 if it does, that means i already increment the array index and therefore the array isn't distinct otherwise i will increment the array cell and continue checking.
And another solution, if you want to find duplicated values.
var values = new [] { 9, 7, 2, 6, 7, 3, 8, 2 };
var sorted = values.ToList();
sorted.Sort();
for (var index = 1; index < sorted.Count; index++)
{
var previous = sorted[index - 1];
var current = sorted[index];
if (current == previous)
Console.WriteLine(string.Format("duplicated value: {0}", current));
}
Output:
duplicated value: 2
duplicated value: 7
http://rextester.com/SIDG48202
I have a list.
It's possible members (x123, y123, z123, a123, b123, c123).//123 is example
This "mylist" may contain a member that starting with x, or may not. Also this is the same for y,z,a,b,c.
If contains a member starts with x:
//Formula Contains X
If Not Contains a member starts with x:
//Formula Not Contains X
//same as all of x,y,z,a,b,c. But unlike a foreach, I must place the formulas at checking time, not after.
How can I do that?
Checks if any items start with 'x' in your list:
bool result = mylist.Any(o => o.StartsWith("x"))
Checks if no items start with 'x' your list:
bool result = !mylist.Any(o => o.StartsWith("x"));
You can use .Any from Linq
bool result = mylist.Any(o => o.StartsWith("x"));
This will iterate on the list and tell you if there is at least one element that starts with "x"
public void Process(List<string> list, string key)
{
if (list.Any(i => i.StartsWith(key)))
{
//Formula Contains key
}
else
{
//Formula Not Contains key
}
}
then you can call
List<string> list = new List<string> { "x123", "y123", "z123", "a123", "b123", "c123"};
Process(list, "x");
Process(list, "a");
List<string> formula = new List<string> { "x123", "y123" };
string variable = "x";
bool containsVariable = formula.Any(s => s.StartsWith(variable));