C# /Linq Yet another Brain Teaser
Friends, there is yet another scenario to solve. I am working it out without applying Linq.But I hope it is good opportunity for me to learn Linq if you share your code in Linq.
It is know as FLAMES
F - Friend
L - Lover
A - Admirer
M - Marry(Husband)
E - Enemy
S - Sister
Problem description:
Two names will be given (male, female).We have to strike out the common letters from both na开发者_如何学Gomes. Then we have to count the number of remaining letters after striking out the common characters from both names. Finally we have to iterate the string FLAMES and striking out the letters in FLAMES until we will reach single character left. The remaining single character shows the relationship. I will explain the process more details in the following example.(Ignore cases and spaces).
Example :
Step 1
Male : Albert
Female : Hebarna
Letters “a”, “e” ,”b” are common in both names.
( Strike those letters from both string , even the name “Hebarna” contains two “a” you are allowed to strike single “a” from both string because The name “Albert” has only single “a”).
The resultant string is
Male : $ l $ $ r t
Female: H $ $ $ r n a
Step 2:
Count the remaining letters from both strings.
Count : 7
Step 3:
Using the count we have to iterate the string “FLAMES” in the following manner
F L A M E S
1 2 3 4 5 6
7
(Here the count 7 ends at F ,so strike F)
you will get
$ L A M E S
(Again start your count from immediate next letter (it should not already be hit out) if it is the last letter (“S”) then start from first letter “F” if ‘F” is not already hit out.
$ L A M E S
(igonre) 1 2 3 4 5
(ignore) 6 7
During counting never consider hit out letters.
$ L $ M E S
1 2 3
ignore 4 ignore 5 6 7
"s" will be hit out.
$ L $ M E $
ignore 1 ignore 2 3
4 ignore 5 6
7
"L" will be hit out
$ $ $ M E $
ignore 1 2 ignore
ignore ignore ignore 3 4 ignore
5 6
7
Finally "M" will be hit out. Then only remaining letter is "E" So albert is enemy to herbana.
Update : Lettter "r" is also common in both names.I forgor to hit it out.Anyhow the process is same as explained.Thanks for pointing it out.
Step1 and Step2
var firstLookup = firstName.ToLookup(c => c.ToLower());
var secondLookup = secondName.ToLookup(c => c.ToLower());
var allChars = firstLookup.Keys.Union(secondLookup.Keys);
int count =
(
from c in allChars
let firstCount = firstLookup[c].Count()
let secondCount = secondLookup[c].Count()
select
firstCount < secondCount ? secondCount - firstCount :
firstCount - secondCount
).Sum()
Step3 (untested)
List<char> word = "FLAMES".ToList();
while (word.Count > 1)
{
int wordCount = word.Count;
int remove = (count-1) % wordCount;
word =
word.Select( (c, i) => new {c, i =
i == remove ? 0 :
i < remove ? i + wordCount + 1 :
i})
.OrderBy(x => x.i)
.Select(x => x.c)
.Skip(1)
.ToList();
}
char result = word.Single();
var count = male.Length + female.Length - male.Intersect( female ).Count();
while (flames.Length > 1)
{
flames = string.Join( '', flames.Where( (c,i) => i != (count % flames.Length) -1 ).ToArray() );
}
That last calculation part that iterates through the flames-letters and removing one after another can be precalculated.
public static Char GetChar(int diff) {
var idx = (diff - 1) % 60;
return "efefmeaelmaafmfaflefefeemsasamfmfallslslesmsasmmaelmlaslslfs"[idx];
}
Some things can be done without linq... unless I totally messed something up.
精彩评论