I need one liner (or close to it) that verifies that given array of 9 elements doesn't contain repeating numbers 1,2,3,...,9. Repeating zeroes do not count (they represent empty cells).
The best I have came out so far is:
var a = new int[9] {1,2,3,4,5,6,7,8,9};
var itIsOk = a.Join(a, i => i, j => j, (x, y) => x)
.GroupBy(y => y).Where(g => g.Key > 0 && g.Count() > 1).Count() == 0;
If you don't want to solve my problems :), could you at least tell if the above algorithm works correctly?
And, yes, a have read this one.
This is about 50-250 times faster than a LINQ solution (depending on how early the duplicate is found):
public static bool IsValid(int[] values) {
int flag = 0;
foreach (int value in values) {
if (value != 0) {
int bit = 1 << value;
if ((flag & bit) != 0) return false;
flag |= bit;
}
}
return true;
}
Lucky for you I built a sudoku solver myself not too long ago :) The whole thing was about 200 lines of C#, and it would solve the toughest puzzles I could find line in 4 seconds or less.
Performance probably isn't that great due to the use of .Count, but it should work:
!a.Any(i => i != 0 && a.Where(j => j != 0 && i == j).Count > 1)
Also, the j != 0 part isn't really needed, but it should help things run a bit faster.
[edit:] kvb's answer gave me another idea:
!a.Where(i => i != 0).GroupBy(i => i).Any(gp => gp.Count() > 1)
Filter the 0's before grouping. Though based on how IEnumerable works it may not matter any.
Either way, For best performance replace .Count > 1 in either of those with a new IEnumerable extension method that looks like this:
bool MoreThanOne(this IEnumerable<T> enumerable, Predictate<T> pred)
{
bool flag = false;
foreach (T item in enumerable)
{
if (pred(item))
{
if (flag)
return true;
flag = true;
}
}
return false;
}
It probably won't matter too much since arrays are limited to 9 items, but if you call it a lot it might add up.
!a.GroupBy(i => i).Any(gp => gp.Key != 0 && gp.Count() > 1)
This is an old question, but I recently was pointed to a 1 line solution using Oracle's custom SQL for doing tree-like structures. I thought it would be nice to convert this into Linq.
You can read more on my blog about how to Solve Sudoku in 1 line of Linq
Here is the code:
public static string SolveStrings(string Board)
{
string[] leafNodesOfMoves = new string[] { Board };
while ((leafNodesOfMoves.Length > 0) && (leafNodesOfMoves[0].IndexOf(' ') != -1))
{
leafNodesOfMoves = (
from partialSolution in leafNodesOfMoves
let index = partialSolution.IndexOf(' ')
let column = index % 9
let groupOf3 = index - (index % 27) + column - (index % 3)
from searchLetter in "123456789"
let InvalidPositions =
from spaceToCheck in Enumerable.Range(0, 9)
let IsInRow = partialSolution[index - column + spaceToCheck] == searchLetter
let IsInColumn = partialSolution[column + (spaceToCheck * 9)] == searchLetter
let IsInGroupBoxOf3x3 = partialSolution[groupOf3 + (spaceToCheck % 3) +
(int)Math.Floor(spaceToCheck / 3f) * 9] == searchLetter
where IsInRow || IsInColumn || IsInGroupBoxOf3x3
select spaceToCheck
where InvalidPositions.Count() == 0
select partialSolution.Substring(0, index) + searchLetter + partialSolution.Substring(index + 1)
).ToArray();
}
return (leafNodesOfMoves.Length == 0)
? "No solution"
: leafNodesOfMoves[0];
}
Why do you want a convoluted line of Linq code, rather than wrapping up an efficient implementation of the test in an extension method and calling that?
var a = new int[9] {1,2,3,4,5,6,7,8,9};
var itIsOk = a.HasNoNonZeroRepeats();
One implementation of NoNonZeroRepeats could be to use the 9 lowest bits of a short to indicate presence of a value in the array, giving an O(length(a)) test with no dynamic memory use. Linq is cute, but unless you're only using it for aesthetic reasons (you don't specifically say that you're writing a sudoku solver using only Linq as an exercise) it seems to be just adding complexity here.
How about:
var itIsOk = a.Where(x => x > 0).Distinct().Count() == a.Where(x => x > 0).Count();
Reasoning: First create an enumeration without 0s. Out of the remaining numbers, if its distinct list is the same length as the actual list, then there are no repeats.
or:
If the list of unique numbers is smaller than the actual list, then you must have a repeated number.
This is the one-liner version. The a.Where(x=>x>0) list could be factored out.
var nonZeroList = a.Where(x => x > 0).ToList();
var itIsOk = nonZeroList.Distinct().Count() == nonZeroList.Count();
I usually frown on solutions that involve captured variables, but I had an urge to write this:
bool hasRepeating = false;
int previous = 0;
int firstDuplicateValue = a
.Where(i => i != 0)
.OrderBy(i => i)
.FirstOrDefault(i =>
{
hasRepeating = (i == previous);
previous = i;
return hasRepeating;
});
if (hasRepeating)
{
Console.WriteLine(firstDuplicateValue);
}
For brevity if not performance, how about
var itIsOk = a.Sum() == a.Distinct().Sum();
The following is simple and fast.
if a.Select(i => Math.Pow(2, i - 1)).ToArray().Sum()==511 ...
Related
I am a C# developer and I am training my coding and algorithm skills on LeetCode.
And now I am handling the problem 5: longest palindromic substring.
I want someone can explain the reason.
My solution version 1 to this problem was:
public string LongestPalindrome(string s)
{
// Step 0: Handles invalid or special cases.
if (string.IsNullOrWhiteSpace(s) ||
s.Length == 1 ||
s.Distinct().Count() == 1 ||
s.Reverse().SequenceEqual(s))
{
return s;
}
if (s.Length == 2)
{
return s.First().Equals(s.Last()) ? s : s.First().ToString();
}
if (s.Distinct().Count() == s.Length)
{
return s.First().ToString();
}
// Step 1: Handles normal cases.
var longestPalindromeSubstring = string.Empty;
for (var index = 0; index < s.Length && s.Length - index > longestPalindromeSubstring.Length; index++)
{
var currentChar = s[index];
var currentCharLastIndex = s.LastIndexOf(currentChar);
if (index == currentCharLastIndex)
{
if (!string.IsNullOrWhiteSpace(longestPalindromeSubstring) ||
longestPalindromeSubstring.Length > 1)
{
continue;
}
longestPalindromeSubstring = currentChar.ToString();
}
var currentCharIndexes = new Stack<int>();
for (var nextIndex = index + 1; nextIndex <= currentCharLastIndex; nextIndex++)
{
if (s[nextIndex] == currentChar)
{
currentCharIndexes.Push(nextIndex);
}
}
while (currentCharIndexes.Any())
{
var relatedIndex = currentCharIndexes.Pop();
var possibleStr = s.Substring(index, relatedIndex - index + 1);
var reversedPossibleStr = new string(possibleStr.Reverse().ToArray());
if (!possibleStr.Equals(reversedPossibleStr) ||
possibleStr.Length < longestPalindromeSubstring.Length ||
possibleStr.Equals(longestPalindromeSubstring))
{
continue;
}
longestPalindromeSubstring = possibleStr;
}
}
return longestPalindromeSubstring;
}
However this solution above was failed to pass the LeetCode validation since the issue: Time Limit Exceeded.
Then I just made a small update, and the solution version 2 passed, the changed part was only adding ToCharArray() method before invoking Reverse() method:
var reversedPossibleStr = new string(possibleStr.ToCharArray().Reverse().ToArray());
if (!possibleStr.Equals(reversedPossibleStr) ||
possibleStr.Length < longestPalindromeSubstring.Length ||
possibleStr.Equals(longestPalindromeSubstring))
{
continue;
}
…………
But I am not sure the reason why it can work, I just guessed that the data in an array will be arranged in a sequence memory space, it may help to improve the performance, could someone explain more detail.
Thank you in advance.
The Reverse method uses EnumerableHelpers.ToArray to fetch the count of the input enumerable. If the enumerable doesn't implement ICollection<T> interface, it will use a list-like approach to creates an array which will extend the array many times. Unfortunately string doesn't implement ICollection<char>, though it knows how many characters it contains, so string.Reverse() is slower than string.ToCharArray().Reverse().
I have to enter grades to a list box and then to see if they are bigger than 5. And if they are bigger than 5 store the ones who are.
This is what i got so far ..
foreach (var item in listBox.Items)
{
if(Convert.ToInt32(item.ToString())) == 5 )
}
You could use Linq
bool bigger = listBox.Items.OfType<int>().Where(x => x > 5);
It might be usefull to convert the result to a list by using
List<int> filtered = listBox.Items.OfType<int>().Where(x => x > 5).ToList();
You can do this:
var largerThan5 = listBox.Items.Where(I => int.Parse(I.ToString()) > 5).ToList();
You cannot use LINQ as listBox.Items are not implement IEnumerable.
Use this for example:
for (var pos = 0; pos < listBox1.Items.Count; pos++)
{
int value;
if (int.TryParse(listBox1.Items[pos]?.ToString(), out value) && value >= 5)
Debug.WriteLine($"Index: {pos}, Value: {value}");
}
I have the following method in my project:
public double CalculateDailyProjectMaxPumpSpm(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pump stroke Max...");
var spm = new List<double>();
if (start == null)
{
for (var i = 0; i < _pumpOneSpm.Count; i++)
{
if (_date[i].Equals(date))
{
spm.Add(_pumpOneSpm[i]);
spm.Add(_pumpTwoSpm[i]);
}
}
}
else
{
for (var i = 0; i < _pumpOneSpm.Count; i++)
{
if (_date[i].Equals(date) &&
DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[i], DateTime.Parse(end)) < 0)
{
spm.Add(_pumpOneSpm[i]);
spm.Add(_pumpTwoSpm[i]);
}
}
}
return _dailyProjectMaxSpm = Math.Round(spm.Max(), 2, MidpointRounding.AwayFromZero);
}
I'm trying to make the method look a little less unwieldy. I had tried:
public double CalculateDailyProjectMaxPumpSpm(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pump stroke Max...");
var spm = start == null ? _pumpOneSpm.Concat(_pumpTwoSpm).Where((t, i) => _date[i].Equals(date)).ToList()
: _pumpOneSpm.Concat(_pumpTwoSpm).Where((t, i) => _date[i].Equals(date) &&
DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[i], DateTime.Parse(end)) < 0).ToList();
_dailyProjectMaxSpm = Math.Round(spm.Max(), 2, MidpointRounding.AwayFromZero);
return _dailyProjectMaxSpm;
}
But when I ran the program I got an Index out of range. Must be non-negative and less than the size of the collection. Parameter name: index error. Now, I couldn't care less what order the elements are added to the new list, just so long as if the conditions are met, they are added. Could anyone help me out with the error? Thanks.
UPDATE
_date is a list of dates pulled from a database, and _time is a list of timestamps pulled from the same database. All variables with the _ is a list pulled from a database. The Count of each list will always be equal to the Count of each other list.
Like sil said, you're concatenating the two lists, resulting in a list with a larger index range. How about this solution, which uses Enumerable.Range() to produce the indexes, then uses a combined version of your two predicates to filter, and finally flattens the list with SelectMany():
public double CalculateDailyProjectMaxPumpSpm(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pump stroke Max...");
var spm = Enumerable
.Range(0, _pumpOneSpm.Count)
.Where(x => _date[x].Equals(date) &&
(start == null ||
(DateTime.Compare(_time[x], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[x], DateTime.Parse(end)) < 0)))
.SelectMany(x => new [] { _pumpOneSpm[x], _pumpTwoSpm[x] });
return _dailyProjectMaxSpm = Math.Round(spm.Max(), 2, MidpointRounding.AwayFromZero);
}
In original method i is in range from 0 to _pumpOneSpm.Count but now from 0 to
_pumpOneSpm.Count + _pumpTwoSpm.Count
Following results in a list of _pumpOneSpm.Count + _pumpTwoSpm.Count items:
_pumpOneSpm.Concat(_pumpTwoSpm).Where((t, i) => _date[i]
And I cannot see LINQ analogue which would be more clear than your first method example using for loops.
Is it easier to use linq to do the same thing as this code? (check and see how many values are equal to the value following):
int[] values = {1,2,3,3,5,6,7};
int counter=0;
for (int f =0; f< values.Length-1; f++)
{
if(values[f]==values[f+1])
{
counter++;
}
}
Yes, you can do this quite easily with Zip in .NET 4:
var count = values.Zip(values.Skip(1), (x, y) => new { x, y })
.Count(pair => pair.x == pair.y);
The trick of combining Zip and Skip(1) takes a little bit of getting your head round, but it's a really neat one. Basically you start with a sequence of n values, and the result is a sequence of n - 1 pairs, each of which contains a value and its successor.
From there, it's just a matter of counting the pairs which are the same :)
Note that the sequence in question will be evaluated twice, so you wouldn't want to do this for anything which was lazily evaluated, or which wouldn't give the same results when evaluated twice.
No I don't think it's easier. The code you have is easy to understand and concise, I wouldn't refactor it with linq. Make sure you test it a bit more though, as you might get an out of bounds error on the last loop.
There exists a very neat solution:
var list = new[] { 1, 2, 3, 3, 5, 6, 7, 7 };
var pairs = SeqModule.Pairwise(list);
var count = pairs.Count(p => p.Item1 == p.Item2);
This requires that you reference the assembly FSharp.Core and you use using Microsoft.FSharp.Collections;. Alternatively, you can implement the Pairwise method as a extension method and thereby avoid using another assembly.
For anyone who might be interested in F#, here is a solution:
let lst = [1;2;3;3;5;6;7;7]
let count = lst |> Seq.pairwise
|> Seq.filter (fun (x, y) -> x = y)
|> Seq.length
Try this:
var set = values.Where((value, i) => i < (values.Length - 1) ? values[i] == values[i + 1] : false);
EDIT:
Sorry, forgot to add set.Count() to get the result :-)
Given that the values are in an array, you can do this:
int duplicates = values.Skip(1).Where((n, i) => n == values[i]).Count();
You could say something like:
private static int CountDoubles( IEnumerable<int> Xs )
{
int? prev = null ;
int count = Xs.Count( curr => {
bool isMatch = prev.HasValue && prev == curr ;
prev = curr ;
return isMatch ;
} ) ;
return count ;
}
but that's neither simpler nor cleaner than your original version. I'd tweak yours slightly, though::
public static int CountDoubles( int[] Xs )
{
int n = 0 ;
for ( int i = 1 ; i < Xs.Length ; ++i )
{
n += ( Xs[i-1] == Xs[i] ? 1 : 0 ) ;
}
return n ;
}
There are two lists of string
List<string> A;
List<string> B;
What is the shortest code you would suggest to check that A.Count == B.Count and each element of A in B and vise versa: every B is in A (A items and B items may have different order).
If you don't need to worry about duplicates:
bool equal = new HashSet<string>(A).SetEquals(B);
If you are concerned about duplicates, that becomes slightly more awkward. This will work, but it's relatively slow:
bool equal = A.OrderBy(x => x).SequenceEquals(B.OrderBy(x => x));
Of course you can make both options more efficient by checking the count first, which is a simple expression. For example:
bool equal = (A.Count == B.Count) && new HashSet<string>(A).SetEquals(B);
... but you asked for the shortest code :)
A.Count == B.Count && new HashSet<string>(A).SetEquals(B);
If different frequencies of duplicates are an issue, check out this question.
If you call Enumerable.Except() on the two lists, that will return an IEnumerable<string> containing all of the elements that are in one list but not the other. If the count of this is 0, then you know that the two lists are the same.
var result = A.Count == B.Count && A.Where(y => B.Contains(y)).Count() == A.Count;
Maybe?
How about a simple loop?
private bool IsEqualLists(List<string> A, List<string> B)
{
for(int i = 0; i < A.Count; i++)
{
if(i < B.Count - 1) {
return false; }
else
{
if(!String.Equals(A[i], B[i]) {
return false;
}
}
}
return true;
}
If you aren't concerned about duplicates, or you're concerned about duplicates but not overly concerned about performance micro-optimisations, then the various techniques in Jon's answer are definitely the way to go.
If you're concerned about duplicates and performance then something like this extension method should do the trick, although it really doesn't meet your "shortest code" criteria!
bool hasSameElements = A.HasSameElements(B);
// ...
public static bool HasSameElements<T>(this IList<T> a, IList<T> b)
{
if (a == b) return true;
if ((a == null) || (b == null)) return false;
if (a.Count != b.Count) return false;
var dict = new Dictionary<string, int>(a.Count);
foreach (string s in a)
{
int count;
dict.TryGetValue(s, out count);
dict[s] = count + 1;
}
foreach (string s in b)
{
int count;
dict.TryGetValue(s, out count);
if (count < 1) return false;
dict[s] = count - 1;
}
return dict.All(kvp => kvp.Value == 0);
}
(Note that this method will return true if both sequences are null. If that's not the desired behaviour then it's easy enough to add in the extra null checks.)