Is there any way to translate the following query
select word
from string1
where Left(word, 1) in (
select Left(word, 1) as firstInitial
from string1
group by Left(word , 1)
having count(*) > 1
)
into LINQ so when you run it on "While Kim kept kicking I ate my Dunkin donut with great gusto" it produces something like
(miss,Match,Match,Match,miss,miss,miss,Match,Match,miss,Match,Match)
The following solution shows one possible approach. To use this, be sure to add the MoreLINQ NuGet package to your project.
using System;
using System.Linq;
using MoreLinq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
var input = "While Kim kept kicking I ate my Dunkin donut with great gusto";
var value = input.Split(' ');
var lagged = value.Lag(1, (current, previous) => new { current = current?.ToLowerInvariant(), previous = previous?.ToLowerInvariant() });
var leaded = value.Lead(1, (current, next) => new { next = next?.ToLowerInvariant() });
var results = lagged.Zip(leaded, (x, y) => x.current?.FirstOrDefault() == x.previous?.FirstOrDefault() ||
x.current?.FirstOrDefault() == y.next?.FirstOrDefault());
Console.WriteLine(string.Join(",", results));
Console.ReadLine();
}
}
}
Basically the code splits the string into multiple words, and then looks at each word (current) and the word before (previous) and after (next) it. It then compares the first letter of current vs that of previous and next.
If you want to return 1 / 0 rather than true / false then change just this line of code:
var results = lagged.Zip(leaded, (x, y) => (x.current?.FirstOrDefault() == x.previous?.FirstOrDefault() ||
x.current?.FirstOrDefault() == y.next?.FirstOrDefault()) ? 1 : 0);
The solution for this won't be as simple as a few lines, but I can try:
First, the simplest but not so elegant for loop method:
var words = string1.Split(' ').ToList();
string[] results = new string[words.Count]; //edited: can use .Count instead of .Count()
for (int i = 0; i < words.Count; i++)
{
if (i == words.Count - 1)
results[i] = char.ToLower(words[i - 1][0]) == char.ToLower(words[i][0]) ? "Match" : "miss";
else if (i == 0)
results[i] = char.ToLower(words[i + 1][0]) == char.ToLower(words[i][0]) ? "Match" : "miss";
else
{
bool leftMatch = char.ToLower(words[i - 1][0]) == char.ToLower(words[i][0]);
bool rightMatch = char.ToLower(words[i + 1][0]) == char.ToLower(words[i][0]);
results[i] = (leftMatch || rightMatch) ? "Match" : "miss";
}
}
What this does is go through each element, if the left or right word has a same initial character, it is a "Match", otherwise it is "miss". For the first and last word it just needs to check one neighbor instead of 2.
Using Enumerable.Range Method (Int32, Int32) of LINQ, as well as the ?: Operator, this can be simplified into a few lines:
var words = string1.Split(' ').ToList();
var results = Enumerable.Range(0, words.Count).Select(i => i == words.Count - 1 ?
char.ToLower(words[i - 1][0]) == char.ToLower(words[i][0]) ? "Match" : "miss" :
i == 0 ?
char.ToLower(words[i + 1][0]) == char.ToLower(words[i][0]) ? "Match" : "miss" :
(char.ToLower(words[i - 1][0]) == char.ToLower(words[i][0]) || char.ToLower(words[i + 1][0]) == char.ToLower(words[i][0])) ? "Match" : "miss" ).ToList();
The ToList() at the end is optional, you can convert ToArray() if you wish.
Related
I need help with a program that'll count the maximum number of 0's between two 1's in a given binary number in c#. For example 1100101(binary for 101) the maximum number of 0's between two 1's are 2. Any help?
This the code for counting the 0's in the string but not the 0's between 1's
string bin = "";
int max = 0;
for (int i = rem.Length - 1; i >= 0; i--)
{
if (rem[i] == '0')
{
bin = bin + rem[i];
c++;
}
else
{
bin = bin + rem[i];
}
}
Try this (updated code):
string num = "1011100";
char[] myChar = num.ToCharArray();
bool blFirst = false; //This will check if there is "1" on first element of the input
bool blLast = false; //This will check if there is "1" on last element of the input
if (myChar[0] == '0') //If the condition is true we will remove this on the result
blFirst = true;
if (myChar[myChar.Length - 1] == '0')
blLast = true;
string[] intArr = num.Split('1').ToArray();
List<string> intResult = new List<string>();
//We will make sure that all results only contains '0' and not empty.
intResult = intArr.Where(x => x.All(y => y == '0') && x != string.Empty).Select(x => x).ToList();
if (blFirst == true)
intResult.RemoveAt(0);
if (blLast == true)
intResult.RemoveAt(intResult.Count - 1);
//After all conditions are met (Get only '0' numbers between 1), that's the time we get the maximum count
intOutput = intResult.Select(x => x).Max(x => x.Length);
A simpler version:
string num = "1011100";
//trim the 0's at the start and the end
num=num.Trim(new Char[] { '0' });
string[] intArr = num.Split(new string[] {"1"}, StringSplitOptions.RemoveEmptyEntries);
int Output = intArr.Max(x => x.Length);
This should work:
public static int CountZerosBetweenOnes(string binary)
{
var indicesOfOnes =
binary.Select((c, i) => new {c, i})
.Where(x => x.c == '1')
.Select(x => x.i);
return
indicesOfOnes
.Zip(indicesOfOnes.Skip(1), (a, b) => b - a - 1)
.DefaultIfEmpty(0)
.Max();
}
It does assume that binary does not contain any characters other than 1 and 0.
If you want a version that accepts an int:
public static int CountZerosBetweenOnes(int binary)
{
var indicesOfOnes =
Convert.ToString(binary, 2)
.Select((c, i) => new {c, i})
.Where(x => x.c == '1')
.Select(x => x.i);
return
indicesOfOnes
.Zip(indicesOfOnes.Skip(1), (a, b) => b - a - 1)
.DefaultIfEmpty(0)
.Max();
}
I tested this with the following test code, which outputs the expected result:
public static void Main(string[] args)
{
test("0000000000000"); // Outputs 0
test("0000100010000"); // Outputs 3
test("1111111111111"); // Outputs 0
test("1000000000001"); // Outputs 11
test("1000000000000"); // Outputs 0
test("0000000000001"); // Outputs 0
test("1010101010101"); // Outputs 1
test("1001000100001"); // Outputs 4
}
static void test(string s)
{
Console.WriteLine(CountZerosBetweenOnes(s));
}
Or run it on .Net Fiddle here: https://dotnetfiddle.net/H2Mt8w
I have a string
string value = "123456789";
now I need to re-arrange the string in the following way:
123456789
1 right
12 left
312 right
3124 left
53124 right
...
975312468 result
Is there a fancy linq one liner solution to solve this?
My current (working but not so good looking) solution:
string items = "abcdefgij";
string result = string.Empty;
for (int i = 0; i < items.Length; i++)
{
if (i % 2 != 0)
{
result = result + items[i];
}
else
{
result = items[i] + result;
}
}
string value = "123456789";
bool b = true;
string result = value.Aggregate(string.Empty, (s, c) =>
{
b = !b;
return b ? (s + c) : (c + s);
});
I actually don't like local variables inside LINQ statements, but in this case b helps alternating the direction. (#klappvisor showed how to live without b).
You can use length of the res as variable to decide from which side to append
items.Aggregate(string.Empty, (res, c) => res.Length % 2 == 0 ? c + res : res + c);
Alternative solution would be zipping with range
items.Zip(Enumerable.Range(0, items.Length), (c, i) => new {C = c, I = i})
.Aggregate(string.Empty, (res, x) => x.I % 2 == 0 ? x.C + res : res + x.C)
EDIT: don't really needed ToCharArray...
Resulting string is chars in evens positions concatenated to chars in odds positions in reverse order:
string value = "123456789";
var evens = value.Where((c, i) => i % 2 == 1);
var odds = value.Where((c, i) => i % 2 == 0).Reverse();
var chars = odds.Concat(evens).ToArray();
var result = new string(chars);
I want to verify that a string does not contain any duplicate characters (from a set of bad characters) in adjacent positions. Previous stack overflow answers on this subject seem to mostly be of the general form:
for(int i = 0; i < testString.Length-1; i++){
if(testString[i] == testString[i+1] && testString[i] == badChar){
//Handle rejection here
}
}
Is it possible to do this kind of verification/validation in LINQ? More generically: is it possible within LINQ to compare the value of each character in a string to the next character in a
testString.Any(c => /*test goes here*/) call?
Anytime you have a class that has Count (or equivalent) property and indexer, you can use Enumerable.Range as base for the LINQ query and perform inside an indexed access similar to the non LINQ code:
bool test = Enumerable.Range(0, testString.Length - 1).Any(i = >
testString[i] == testString[i + 1] && testString[i] == badChar)
You could use Pairwise from moreLINQ library:
if(testString.Pairwise((n, m) => new {n, m}).Any(x => x.n == x.m && x.n == badChar))
// do something
If you want to use pure LINQ you could hack it with Skip/Zip combination:
if(testString.Zip(testString.Skip(1), (n, m) => new {n, m})).Any(x => x.n == x.m && x.n == badChar))
// do something
But both these solutions will be much slower then for loop-based solution, so I'd advice against doing that.
How about the egregious misuse of the aggregate function? I like to think this answer is more of an example of what not to do, even if it is possible. A while and string.indexOf are probably the most appropriate to this problem.
var items = "ab^cdeef##gg";
var badChars = new[] {'^', '#', '~'};
var doesAdjacentDupeExist = false;
var meaninglessAggregate = items.Aggregate((last, current) =>
{
if (last == current && badChars.Contains(last))
{
doesAdjacentDupeExist = true;
};
return current;
});
This is not as clever, but it does work. It trades the setting of an outside variable inside the query (bad), for relying on index and elementAt (not great).
var items = "abcdefffghhijjk";
var badChars = new[] { 'f', 'h' };
var indexCieling = items.Count() - 1;
var badCharIndexes = items.Select((item, index) =>
{
if (index >= indexCieling)
{
return null as int?;
}
else
{
if (item == items.ElementAt(index + 1) && badChars.Contains(item))
{
return index as int?;
}
else
{
return null as int?;
}
}
});
var doesAdjacentDupeExist = badCharIndexes.Any(x => x.HasValue);
I'm trying to write a linq query that uses an if statement.
In the code below I'm searching for matches of
n.SAU_ID = sau.SAUID where
ReportingPeriod column contains "Oct1" then
FiscalYear - aprYearDiff = sau.SAUYearCode.
Else
FiscalYear - octYearDiff = sau.SAUYearCode.
My code is only giving matches for the SAUID and "Oct1".
What code is needed to implement theese statements?
int FiscalYear = 2014;
List<String> addtowns = new List<string>();
List<Stage_Reorg> reorg = _entities.Stage_Reorg.ToList();
int aprYearDiff = 2;
int octYearDiff = 1;
foreach (var sau in reorg)
{
addtowns.AddRange(_entities.Stage_EPSSubsidySADCSDTown
.Where(n => n.SAU_ID == sau.SAUID
&& (n.ReportingPeriod == "Oct1"
? (FiscalYear - aprYearDiff) == sau.SAUYearCode
: (FiscalYear - octYearDiff) == sau.SAUYearCode))
.Select(n => n.TownCode ));
}
This is a bad idea anyway. Transform the condition to
(n.ReportingPeriod == "Oct1" && (FiscalYear - aprYearDiff) == sau.SAUYearCode)
|| (n.ReportingPeriod != "Oct1" && (FiscalYear - octYearDiff) == sau.SAUYearCode)
Here is a possible way but this probably won't work with EF. You will need to load all records into memory then perform the filtering:
addtowns.AddRange(_entities.Stage_EPSSubsidySADCSDTown
.Where(n => {
bool b = n.ReportingPeriod == "Oct1"
? (FiscalYear - aprYearDiff) == sau.SAUYearCode
: (FiscalYear - octYearDiff) == sau.SAUYearCode);
return b && n.SAU_ID == sau.SAUID;
}).Select(n => n.TownCode ))
I have made a 5 dice yahtzee game, and i am trying to make it work for 6 dice aswell, can you help this two functions more universal my code as of this moment :)
i have prepared dice values in list int[] i
and I have detected fullHouse with this very simple method:
Array.Sort(i);
if( ((i[0] == i[1]) && (i[1] == i[2]) && (i[3] == i[4]))
{
... sum it up
}
else if((i[0] == i[1]) && (i[2] == i[3]) && (i[3] == i[4]))
{
... sum it up
}
I have detected straight with this very simple method
Array.Sort(i);
if( ((i[0] == 1) &&
(i[1] == 2) &&
(i[2] == 3) &&
(i[3] == 4) &&
(i[4] == 5)) ||
((i[0] == 2) &&
(i[1] == 3) &&
(i[2] == 4) &&
(i[3] == 5) &&
(i[4] == 6)) )
{
... sum it up
}
Thx in advance
Writing the logic completely manually like that produces code that is unwieldy and hard to extend. Abstracting things a little with LINQ will help a lot.
To detect a full house, group rolls by value and check the cardinality of each group (I am using i as the array of rolls to follow the original code, but that's a bad name for an array):
var groups = i.GroupBy(i => i);
Then you can check for a full house very easily:
var hasFullHouse = groups.Any(g1 =>
g1.Count >= 3 && groups.Except(g1).Any(g2 => g2.Count >= 2)
);
"If there is any group with at least 3 dice and there is also a
different group with at least 2 dice, you have a full house."
To check for a straight, iterate over the groups in order. For each one, check if the group representing the previous die roll exists. If it does increment a counter, otherwise reset the counter. If the counter ever reaches 5 there is a straight:
var runLength = 0;
var map = groups.ToDictionary(g => g.Key, g => g.Count);
foreach (var roll in map.Keys.OrderBy(k => k))
{
var runLength = map.Contains(roll - 1) ? runLength + 1 : 0;
if (runLength == 5)
{
// straight detected
}
}
Both of these methods will work regardless of the number of dice in the game.
if you have list of ints you can check if they are consecutive values (straight)
bool isfullhouse = !list.Select((i,j) => i-j).Distinct().Skip(1).Any();
return isfullhouse;
you can make your array a list by:
var list = yourArray.ToList();
second one can be modified to look like:
var list = yourArray.ToList().Skip(2);
if(yourArray[0]==yourArray[1]) // checks XX
{
var distincted = list.Distinct();
if(distincted.Count()==1) // checks if other values are equal
{
if(distincted[0]!=yourArray[0]) // checks if not XXXXXX
return true;
}
}
return false;
it will check if there is a full house like XX YYYY (it can have any number of Y's)