First off, sorry if the title isn't clear or descriptive; I didn't know what to write exactly.
I'm wondering if there is a better way to do this operation:
bool result = variable1.innerValue.level2.innerValue == 1 ||
variable1.innerValue.level2.innerValue == 2 ||
variable1.innerValue.level2.innerValue == 3;
We can't write something like:
bool result = variable1.innerValue.level2.innerValue == (1 || 2 || 3);
This will give a syntax error.
Any ideas?
You could use a collection as placeholder and Enumerable.Contains:
if(new[]{1, 2, 3}.Contains(variable1.innerValue.level2.innerValue))
{
}
or, for what it's worth, this extension:
public static bool In<T>(this T source, params T[] list)
{
if(null==source) throw new ArgumentNullException("source");
return list.Contains(source);
}
which enables you to write this:
if(variable1.innerValue.level2.innerValue.In(1, 2, 3))
{
}
What are your favorite extension methods for C#? (codeplex.com/extensionoverflow)
In this case. you can do Enumerable.Range(1, 3).Contains(variable1.innerValue.level2.innerValue).
using System.Linq;
...
bool result = new[] {1, 2, 3}.Contains(variable1.innerValue.level2.innerValue);
var listToCheck = new int[]{1,2,3};
var innerValue = variable1.innerValue.level2.innerValue;
bool result = listToCheck.Contains(innerValue);
Honestly, the first thing that comes to my mind is the good old Introduce Explaining Variable refactoring, which not only reduces the duplication but also makes your code more self-explanatory:
var innerValue = variable1.innerValue.level2.innerValue;
bool result = innerValue == 1 || innerValue == 2 || innerValue == 3;
How about
(new List<int>(){1,2,3}).Exists(i=>i == variable1.innerValue.level2.innerValue)
Related
I have a list of integers and I need to find the last occurrence that matches a predicate. To use a very simple example:
var myList = new List<int> { 1, 5, 6, 20, 18, 2, 3, 0, 4 };
var lastMatch = myList.FindLast(e => e == 0 || e == 2);
This seems like the perfect usecase for FindLast. Problem is that this method returns default(T) if nothing was found, which in the case of integers, is actually a valid value 0. So the question is, if this method returns 0, how can I know if it found something or not? Is there a better method for this case with ints?
Use FindLastIndex instead. If the index is negative no match was found. If it isn't negative: that's the index you want, so: use the indexer with that index.
As an alternative to #MarcGravell answer:
Instead of the List FindLast method, you could use the Linq Last extension method overload that takes a predicate as an argument. It will throw an exception if no match is found.
See Last documentation
In general case when we have IEnumerable<T> with arbitrary T (we can't play trick with int? now)
we can implement an extension method:
public static partial class EnumerableExtensions {
public static int LastIndex<T>(this IEnumerable<T> source,
Predicate<T> predicate) {
if (source is null)
throw new ArgumentNullException(nameof(source));
if (predicate is null)
throw new ArgumentNullException(nameof(predicate));
int result = -1;
int index = -1;
foreach (T item in source) {
index += 1;
if (predicate(item))
result = index;
}
return result;
}
}
And then
var lastMatch = myList.LastIndex(e => e == 0 || e == 2);
Let's say I'm working with an object of class thing. The way I'm getting this object is a bit wordy:
BigObjectThing.Uncle.PreferredInputStream.NthRelative(5)
I'd like to see if this thing is equal to x or y or z. The naive way to write this might be:
BigObjectThing.Uncle.PreferredInputStream.NthRelative(5) == x ||
BigObjectThing.Uncle.PreferredInputStream.NthRelative(5) == y ||
BigObjectThing.Uncle.PreferredInputStream.NthRelative(5) == z
In some languages I could write something like this:
BigObjectThing.Uncle.PreferredInputStream.NthRelative(5) == x |= y |= z
but C# doesn't allow that.
Is there a C#-idiomatic way to write this test as a single expression?
Just use a variable:
var relative = BigObjectThing.Uncle.PreferredInputStream.NthRelative(5);
return relative == x || relative == y || relative == z;
Or if you want to get fancy with a larger set of things:
var relatives = new HashSet<thing>(new[] { x, y, z });
return relatives.Contains(BigObjectThing.Uncle.PreferredInputStream.NthRelative(5));
An extension method would simulate this:
public static bool EqualsAny(this Thing thing, params object[] compare)
{
return compare.Contains(thing);
}
bool result = BigObjectThing.Uncle.PreferredInputStream.NthRelative(5).EqualsAny(x, y, z);
C# doesn't have a default syntax for such an OR-like comparison afaik.
As others have pointed out a collection is one way you could do this. If you wanted to have a little more flexibility than using Contains (which only really lets you test x.Equals(y)), and even support chaining by &= in additon to |=, I'd suggest the Any or All extension methods built into .NET.
var compares = new[] { x, y, z };
var relative = BigObjectThing.Uncle.PreferredInputStream.NthRelative(5);
// Simulate |= behavior
return compares.Any(x => relative == x);
// Simulate &= behavior
return compares.All(x => relative == x);
// A more complex test chained by OR
return compares.Any(x => relative.SomeProperty == x.SomeProperty);
// A less readable but one-line approach
return (new [] {x, y, x}).Any(x => BigObjectThing.Uncle.PreferredInputStream.NthRelative(5) == x);
You could put your objects in a Collection first and then use Contains().
var relatives = new Collection<Thing> { x, y, z };
if (relatives.Contains(BigObjectThing.Uncle.PreferredInputStream.NthRelative(5)))
{
...
}
This could be shortened even more (at the sake of readability):
if (new Collection<Thing> { x, y, z }.Contains(BigObjectThing.Uncle.PreferredInputStream.NthRelative(5)))
{
...
}
Do such stuff in one expression? This calls for my mad LINQ skillz!
Working sample (http://ideone.com/VNTFnz):
using System.Linq;
public class Test
{
static int getStuff()
{
return 1;
}
public static void Main()
{
if ((from option in new int[] {1, 2, 3}
let thing = getStuff()
where option == thing
select option).Any())
System.Console.WriteLine("in the list!");
}
}
Translated for your case, it would be something like this:
if ((from option in new Thing[] {x, y, z}
let thing = BigObjectThing.Uncle.PreferredInputStream.NthRelative(5)
where option == thing
select option).Any())
System.Console.WriteLine("in the list!");
I'm not saying you should do it this way, but hey, you get the boolean result, you can check against any number of values in place of x, y, and z! Also, this doesn't limit you to comparison with ==, you can use anything you like in its place.
And hey, one expression!
Jokes aside, thinking up weird ways of doing what you wanted to do is fun, but you really should put the result of BigObjectThing.Uncle.PreferredInputStream.NthRelative(5) into a variable!
I am trying to read in a file which is essentially a list of integers, seperated by a line. Obviously, file input can never be trusted so I need to filter out non-integers.
1
2
3
4
I know the as operator usually converts if it can and then assigns a null, however because int isn't nullable this isn't the case. I thought that perhaps I could cast to Nullable<int>. I have never really delved into this, I thought perhaps I could do:
var lines = File.ReadAllLines("");
var numbers = lines.Select(line => line as int?).Where(i => i != null);
I know that I could get potentially get around this by doing:
var numbers = lines.Select(line =>
{
int iReturn = 0;
if (int.TryParse(line, out iReturn ))
return iReturn;
else
return null;
}).Where(i => i != null);
I also could potentially do it as an extension method.
I was just looking for a neat, concise way of doing the cast in a statement and also understanding why my code is invalid.
I'm always using this simple extension method:
public static int? TryGetInt(this string item)
{
int i;
bool success = int.TryParse(item, out i);
return success ? (int?)i : (int?)null;
}
Then it's easy:
var numbers = lines.Select(line => line.TryGetInt())
.Where(i => i.HasValue)
.Select(i => i.Value);
You can also use int.TryParse without the extension, but that is undocumented hence might stop working in future:
int i = 0;
var numbers = lines.Where(line => int.TryParse(line, out i))
.Select(line => i);
Edit
"also understanding why my code is invalid"
relevant code:
if (int.TryParse(line, out iReturn ))
return iReturn;
else
return null;
It would work if you'd replace
else
return null;
with
else
return (int?)null;
because you are returning an int, but null is not convertible implicitly to an int.
There isn't a concise way to do this because here you don't need to cast (you cannot cast) -- you need to convert from one type to another. The types of course are int and string (so not exactly "any" types), but as in the general case any conversion between unrelated types cannot be done "just like that".
Nope. C# is deliberately cautious about changing strings to numbers.
You can make your code shorter (no more nulls) using a foreach loop
var numbers = new List<int>();
foreach(string line in lines)
{
int n;
if (int.TryParse(line, out n))
numbers.Add(n);
}
If I understand you correctly and you want just filter the non integer lines, maybe regex is an option?
var lines = File.ReadAllLines("");
var numbers = lines.Where(i => Regex.IsMatch(i, "[0-9]+"));
Here's the best I came up with:
Use this extension method:
public static class Int32Extensions
{
public static int? ParseOrDefault(this string text)
{
int iReturn = 0;
if (int.TryParse(text, out iReturn))
{
return iReturn;
}
return null;
}
}
Like this:
var query = lines.Select(x => x.ParseOrDefault()).Where(x => x.HasValue);
You can create and extension method
public static int? ToInt(this string s, int default){ ... }
and use it in LINQ:
var lines = File.ReadAllLines(path);
var numbers = lines.Select(line => line.ToInt())
.Where(i => i != null);
I have the following list of distinct strings:
"A"
"B"
"C"
If I want the item after A, I get B. After B, I get C. After C, I get A. Currently I have the following code, but for some reason it feels to me that there is a better way to go about this (maybe?).
private string GetNext(IList<string> items, string curr)
{
if (String.IsNullOrWhitespace(curr))
return items[0];
var index = items.IndexOf(curr);
if (index == -1)
return items[0];
return (index + 1 == items.Count) ? items[0] : items[index + 1];
}
I'm definitely open to a LINQ-esque way of doing this as well :)
The solution you have is functionally correct but it's performance leaves a little to be desired. Typically when dealing with a list style structure you would expect that GetNext would return a result in O(1) time yet this solution is O(N).
public sealed class WrappingIterator<T> {
private IList<T> _list;
private int _index;
public WrappingIterator<T>(IList<T> list, int index) {
_list = list;
_index = index;
}
public T GetNext() {
_index++;
if (_index == _list.Count) {
_index = 0;
}
return _list[_index];
}
public static WrappingIterator<T> CreateAt(IList<T> list, T value) {
var index = list.IndexOf(value);
return new WrappingIterator(list, index);
}
}
The initial call to CreateAt is O(N) here but subsequent calls to GetNext are O(1).
IList<string> list = ...;
var iterator = WrappingIterator<string>.CreateAt(list, "B");
Console.WriteLine(iterator.GetNext()); // Prints C
Console.WriteLine(iterator.GetNext()); // Prints A
Console.WriteLine(iterator.GetNext()); // Prints B
I think maybe you can change the line
return (index + 1 == items.Count) ? items[0] : items[index + 1];
for something like
return items[(index + 1) % items.Count];
I can see some optimization if you track the current index rather than the current string, but to do that the list of items would have to be fixed, i.e. not change.
You could also return items[(index + 1) % items.Count];
Otherwise that code looks fine to me, but perhaps someone has a more clever solution.
LINQ is not the appropriate tool here.
It sounds as if a LinkedList<T> would be the better collection here:
var linkedItems = new LinkedList<String>(items);
LinkedListNode current = linkedItems.Find("C");
String afterC = current.Next == null ? linkedItems.First.Value : current.Next.Value;
Here are the pros and cons of a LinkedList compared to a List.
A linq way:
var result = (from str in list
let index = list.IndexOf(curr) + 1
select list.ElementAtOrDefault(index) ?? list[0]).First();
You can use the mod operator to simplify this a bit and combine everything into one statement:
return items[((String.IsNullOrWhitespace(curr)
? 0
: items.IndexOf(curr)) + 1) % items.Count]
Its definitely shorter, but i'm not sure weather its more readable, too :)
I think the best solution is in the below link, I tried it out and works like charm.
http://www.dotnetperls.com/sort-list
How can I test if value of int is for example 1,2,4 or 5? I thought i could do something like this but apparently not.
if(someInt == (1||2||4||5))
Use LINQ:
if ((new[] {1,2,4,5}).Contains(someInt))
Write an extension method
static class MiscExtensions
{
static bool EqualToAny<T>(this T i, params T[] items)
{
return items.Any(x => x.Equals(i));
}
}
And use it like so
static class Program
{
static void Main(string[] args)
{
int myNumber = 5;
if (myNumber.EqualToAny(1, 2, 3, 4, 5))
Console.WriteLine("Hello, World");
}
}
As an alternative you can use:
switch(someInt)
{
case 1:
case 2:
case 4:
case 5:
DoYourStuff();
break;
}
There are two ways I can think of.
Or all the comparisons.
if (someInt == 1 || someInt == 2 || someInt == 4 || someInt == 5) {
}
Or for a more flexible solution see if someInt is in an array.
if (Array.BinarySearch(new[] { 1, 2, 4, 5 }, someInt ) != -1) {
}
You need to write your if statement like this
if (someInt==1 || someInt==2 || someInt==4 || someInt==4)
Or you could use a switch statement
switch (someInt)
{
case 1:
case 2:
case 4:
case 5:
// do something
break;
}
Breaking down your attempted code is quite interesting. You wrote:
if(someInt == (1||2||4||5))
I guess in your head you read it as, if someInt equals 1 or 2 or 4 or 5. And if computers behaved like humans then this would work. But we all know that computers don't behave like that!
The == equality operator, a binary operator, returns true when its two operands are equal. So that means, in your version, if it compiled, you would need someInt to be equal to (1||2||4||5). And for that to even be meaningful, we would need (1||2||4||5) to evaluate to a single value, instead of producing a compile error. And, if it did evaluate to a single value, then it could not have the meaning which you want. Because you want the test to return true when someInt is equal to one of four candidate values.
The bottom line is that == tests for exact equality between precisely two values.
You can't do it like that. Instead use:
if(someInt == 1 || someInt == 2 || someInt == 4 || someInt == 5)
Or also you could use something like this:
if((new List<int>() {1,2,4,5}).Contains(someInt) == true)