Extract char by sequence in a string vb 2010 - c#

I have a text in richtextbox1, I want to extract each 3 char of the string and so on, like:
richtextbox1.text = "It's Chrismas time"
Result, Sequence of 3 from Right to Left: "Isrmte"
Result, Sequence of 3 from Left to Right: "etmrsI"
How can I do it ?
Code can be in C# 2010. I will translate to vb.net 2010.

How about richtextbox1.text.Where((c, i) => i % 3 == 0)?
Or RTL: richtextbox1.text.Reverse().Where((c, i) => i % 3 == 0)
In VB: richtextbox1.text.Where(Function(c, i) i Mod 3 = 0)
However, your example does not show extracting every third character -- your example ignores whitespace, which you might do this way:
text.Where(Function(c) Not Char.IsWhiteSpace(c)).Where(Function(c, i) i Mod 3 = 0)
To take the text and put it into another textbox, you could do this:
textbox2.text = String.Join("", textbox1.text
.Where(Function(c) Not Char.IsWhiteSpace(c))
.Where(Function(c, i) i Mod 3 = 0))
Here's my test code copied directly from VS 2010:
Dim text = "It's Chrismas time"
Console.WriteLine(String.Join("",
text.Where(Function(c) Not Char.IsWhiteSpace(c)) _
.Where(Function(c, i) i Mod 3 = 0)))

Related

Reimplement an algorithm to create a refine list

I'm trying to reimplement an algorithm to create a refine keywords list. I don't have the original source code, only the tool .exe file, so I only have the input and the expected output.
The problem here is that the output of my function doesn't match with the output of the original one. Here's the code that I'm using:
string[] inputLines = File.ReadAllLines("Input.txt");
Dictionary<string, int> keywordsCount = new Dictionary<string, int>();
List<string> refineList = new List<string>();
//Get Keywords Count
foreach (string fileName in inputLines)
{
string[] fileNameSplitted = fileName.Split('_');
for (int i = 0; i < fileNameSplitted.Length; i++)
{
string currentKeyWord = fileNameSplitted[i];
if (!string.Equals(currentKeyWord, "SFX", StringComparison.OrdinalIgnoreCase))
{
if (keywordsCount.ContainsKey(fileNameSplitted[i]))
{
keywordsCount[fileNameSplitted[i]] += 1;
}
else
{
keywordsCount.Add(fileNameSplitted[i], 1);
}
}
}
}
//Get final keywords
foreach (KeyValuePair<string, int> keyword in keywordsCount)
{
if (keyword.Value > 2 && keyword.Key.Length > 2)
{
refineList.Add(keyword.Key);
}
}
The input file:
SFX_AMB_BIRDSONG
SFX_AMB_BIRDSONG_MISC
SFX_AMB_BIRDSONG_SEAGULL
SFX_AMB_BIRDSONG_SEAGULL_BUSY
SFX_AMB_BIRDSONG_VULTURE
SFX_AMB_CAVES_DRIP
SFX_AMB_CAVES_DRIP_AUTO
SFX_AMB_CAVES_LOOP
SFX_AMB_DESERT_CICADAS
SFX_AMB_EARTHQUAKE
SFX_AMB_EARTHQUAKE_SHORT
SFX_AMB_EARTHQUAKE_STREAMED
SFX_AMB_FIRE_BURNING
SFX_AMB_FIRE_CAMP_FIRE
SFX_AMB_FIRE_JET
SFX_AMB_FIRE_LAVA
SFX_AMB_FIRE_LAVA_DEEP
SFX_AMB_FIRE_LAVA_JET1
SFX_AMB_FIRE_LAVA_JET2
SFX_AMB_FIRE_LAVA_JET3
SFX_AMB_FIRE_LAVA_JET_STOP
SFX_AMB_UNDW_BUBBLE_RELEASE
SFX_AMB_UNDW_BUBBLE_RELEASE_AUTO
SFX_AMB_WATER_BEACH1
SFX_AMB_WATER_BEACH2
SFX_AMB_WATER_BEACH3
SFX_AMB_WATER_CANALS
SFX_AMB_WATER_FALL_HUGE
SFX_AMB_WATER_FALL_NORMAL
SFX_AMB_WATER_FALL_NORMAL2
SFX_AMB_WATER_FALL_NORMAL3
SFX_AMB_WATER_FOUNTAIN
SFX_CS_LUX_PORTAL_LIGHTNING
SFX_CS_LUX_PORTAL_LIGHTNING1
SFX_CS_LUX_PORTAL_LIGHTNING2
SFX_CS_LUX_PRIEST_COWER
SFX_CS_LUX_PRIEST_MEDAL
SFX_CS_LUX_PRIEST_MEDITATE
SFX_CS_LUX_PRIEST_SCREAM
SFX_CS_LUX_PRIEST_SNIFF1
SFX_CS_LUX_PRIEST_SNIFF2
SFX_CS_LUX_PRIEST_SPIRITS
SFX_CS_LUX_PRIEST_SPIRITS2
SFX_CS_LUX_PRIEST_SPIRITS3
SFX_CS_LUX_PRIEST_SURPRISE
SFX_MON_BM05_TOO_WALK1
SFX_MON_BM05_TOO_WALK2
SFX_MON_BM06_SQU_WALK1
SFX_MON_BM06_SQU_WALK2
SFX_MON_BR06_HAL_ATTACK1
SFX_MON_BR06_HAL_ATTACK2
SFX_MON_BR06_HAL_DIE
SFX_MON_BR06_HAL_HIT
SFX_MON_BR06_HAL_IDLE
SFX_MON_BR06_HAL_IDLE_EATING
SFX_MON_BR06_HAL_LAND1
SFX_MON_BR06_HAL_LAND2
SFX_MON_BR06_HAL_SCRAPE
SFX_MON_BR06_HAL_SLAM
SFX_MON_BR06_HAL_SURPRISE
SFX_MON_BR06_HAL_WALK1
SFX_MON_BR06_HAL_WALK2
SFX_MON_BU01_MUM_ATTACK1
SFX_MON_BU01_MUM_ATTACK2
SFX_MON_BU01_MUM_DIE
SFX_MON_BU01_MUM_HIT
SFX_MON_BU01_MUM_IDLE_RETRIEVE
SFX_MON_BU01_MUM_IDLE_RETRIEVE_GROW
SFX_MON_BU01_MUM_SURPRISE
SFX_MON_BU01_MUM_WALK1
SFX_MON_BU01_MUM_WALK2
SFX_WATER_SPLASH_BIG
SFX_WATER_SPLASH_BIG1
SFX_WATER_SPLASH_BIG2
SFX_WATER_SPLASH_BIG3
SFX_WATER_SPLASH_MED1
SFX_WATER_SPLASH_MED2
SFX_WATER_SPLASH_MED3
SFX_WATER_SPLASH_MEDIUM
SFX_WATER_SPLASH_OUT
SFX_WATER_SPLASH_OUT1
SFX_WATER_SPLASH_OUT2
SFX_WATER_SPLASH_SMALL
And the expected output (from the original tool):
AMB
MON
WATER
LUX
BR06
HAL
SPLASH
PRIEST
FIRE
BU01
MUM
LAVA
BIRDSONG
WALK1
WALK2
JET
IDLE
EARTHQUAKE
FALL
SURPRISE
BIG
CAVES
What should I modify to make that my method matches with the original output?
Thanks in advance!
-------EDIT
I've done some new discoveries:
->It is a method of approximately 100-130 lines.
->Use the Visual Basic methods InStr, Len, Right and Left
->Discards the word "SFX", and all words less than 3 characters long.
->It uses a combobox as a temporary list where it puts all the words that
appear more than once, and from here it takes out some words, which are the ones that are shown in the combobox visible to the user.
->For the first test case, that I've published, this is the discarded words list:
UNDW
BM05
BM06
SEAGULL
DRIP
BUBBLE
PORTAL
TOO
SQU
OUT
AUTO
RELEASE
NORMAL
LIGHTNING
SPIRITS
ATTACK1
ATTACK2
DIE
HIT
RETRIEVE
I could finally get it!!
I could finally figure it out, I had to use OllyDbg,Numega SmartCheck, and VB Decompiler tools, a lot of patience and voilà.
Here is the code, I've done it in VB.Net due to similarity with VB6:
'Clear comboboxes
Combo2.Items.Clear()
Combo3.Items.Clear()
'Start refining
Dim listboxItemsCount As Integer = listbox_SfxItems.Items.Count - 1
'Split only six words
For numberOfIterations As Integer = 0 To 5
'Iterate listbox items
For sfxItemIndex As Integer = 0 To listboxItemsCount
'Iterate listbox items to find matches
For sfxItemIndexSub As Integer = 0 To listboxItemsCount
'Skip the line that we are checking in the previus loop
If sfxItemIndex = sfxItemIndexSub Then
Continue For
End If
'Get item from listbox
Dim currentSfx As String = listbox_SfxItems.Items(sfxItemIndex)
Dim wordToCheck As String = currentSfx
'Split words
If numberOfIterations > 0 Then
For wordIndex = 1 To numberOfIterations
If InStr(1, wordToCheck, "_", CompareMethod.Binary) Then
Dim wordLength As Integer = Len(wordToCheck) - InStr(1, wordToCheck, "_", CompareMethod.Binary)
wordToCheck = Microsoft.VisualBasic.Right(wordToCheck, wordLength)
End If
Next
End If
If InStr(1, wordToCheck, "_", CompareMethod.Binary) Then
Dim wordLength As Integer = InStr(1, wordToCheck, "_", CompareMethod.Binary) - 1
wordToCheck = Microsoft.VisualBasic.Left(wordToCheck, wordLength)
End If
'Find matches
If StrComp("SFX", wordToCheck) <> 0 Then
If Len(wordToCheck) > 2 Then
currentSfx = listbox_SfxItems.Items(sfxItemIndexSub)
If InStr(1, currentSfx, wordToCheck, CompareMethod.Binary) Then
'Get combo items count
Dim addNewItem As Boolean = True
For comboboxIndex As Integer = 0 To Combo2.Items.Count - 1
Dim comboWordItem As String = CType(Combo2.Items(comboboxIndex), ComboItemData).Name
'Check for duplicated
If InStr(1, comboWordItem, wordToCheck, CompareMethod.Binary) = 0 Then
Continue For
End If
'Update combo item with the word appearances count
currentSfx = CType(Combo2.Items(comboboxIndex), ComboItemData).Name
If StrComp(currentSfx, wordToCheck) = 0 Then
'Get current item data
Dim currentItemData As Integer = CType(Combo2.Items(comboboxIndex), ComboItemData).ItemData
'Update value
currentItemData += 1
CType(Combo2.Items(comboboxIndex), ComboItemData).ItemData = currentItemData
End If
'Don't add items in the combobox and quit loop
addNewItem = False
Exit For
Next
'Check if we have to add the new item
If addNewItem Then
Combo2.Items.Add(New ComboItemData(wordToCheck, 0))
End If
End If
End If
End If
Next
Next
Next
'Check final words
Combo3.Items.Add("All")
Combo3.Items.Add("HighLighted")
Dim quitLoop As Boolean = False
Do
If Combo2.Items.Count > 0 Then
Dim itemToRemove As Integer = -1
'Get max value from the remaining words
Dim maxWordAppearances As Integer = 0
For itemIndex As Integer = 0 To Combo2.Items.Count - 1
Dim itemData As Integer = CType(Combo2.Items(itemIndex), ComboItemData).ItemData
maxWordAppearances = Math.Max(maxWordAppearances, itemData)
Next
'Get the item with the max value
For index As Integer = 0 To Combo2.Items.Count - 1
Dim itemData As Integer = CType(Combo2.Items(index), ComboItemData).ItemData
If itemData = maxWordAppearances And itemToRemove = -1 Then
itemToRemove = index
End If
Next
'Remove and add items
Dim itemStringName As String = CType(Combo2.Items(itemToRemove), ComboItemData).Name
Combo3.Items.Add(itemStringName)
Combo2.Items.RemoveAt(itemToRemove)
'Check if we have to skip this loop
If maxWordAppearances <= 5 Then
quitLoop = True
End If
End If
Loop While quitLoop <> True
'Select the first item
Combo3.SelectedIndex = 0
Not sure if it could be optimized, but works as the original one, and outputs the same words with the same order.
If you want to test it, requires the following controls:
two comboboxes, Combo2 is the temporal one, and Combo3 the one that the user views. It also requires a listbox with the items to check.
The comboItemData class has been extracted from this site: https://www.elguille.info/colabora/puntonet/alvaritus_itemdataennet.htm
I've renamed Cls_lista to ComboItemData
How about taking it as a block of text, splitting on line endings or underscores and getting the unique remnants:
File.ReadAllText(path)
.Split(new[]{'\r','\n','_'},StringSplitOptions.RemoveEmptyEntries)
.Distinct();
Hang on.. maybe it's only words three plus length, that appear thrice or more:
File.ReadAllText(path)
.Split(new[]{'\r','\n','_'},StringSplitOptions.RemoveEmptyEntries)
.GroupBy(w => w)
.Where(g => g.Key.Length > 2 && g.Count() > 2)
.Select(g => g.Key)
If you have a fixed list of words to exclude you can do e.g. .Except(new[]{ "SFX", "..." }) on the end..
You can do it with plain LINQ, use a GroupBy and convert it to a dictionary. On that Dictionary you can add additional criteria where you e.g. check the minimum amount of occurrences. You don't need to worry about several if-else conditions and keeps it pretty readable:
string[] inputLines = File.ReadAllLines("Input.txt");
var output = inputLines
.SelectMany(s =>
s.Split('_')
.Where(w => w != "SFX")
)
.GroupBy(g => g)
.ToDictionary(s => s.Key, s => s.Count())
.Where(w => w.Key.Length > 2 && w.Value > 2);
I gave it a go. Can't figure out the ordering, and the performance is not top notch, but you get your required output selection for your one given example.
"SFX" could be excluded due to being (a) contained in all input items, or (b) the very first part of each input item, but I have kept it as a hard-coded string to exclude, in addition to "PORTAL". I really have no idea why "PORTAL" is excluded in the output.
Here, Input is a string[] with the example input provided in the question post.
var excludedWords = new[] { "SFX", "PORTAL" };
var feasibleWords = Input
.SelectMany(str => str.Split('_'))
.Where(word =>
word.Length > 2 &&
!excludedWords.Contains(word));
var repeatedWords = feasibleWords
.GroupBy(word => word)
.Where(gr => gr.Count() > 2)
.ToDictionary(
gr => gr.Key,
gr => gr.Count());
var serialWords = feasibleWords
.Except(repeatedWords.Keys)
.GroupBy(word => Regex.Replace(word, #"[\d]", string.Empty))
.Where(gr =>
gr.Contains(gr.Key) &&
gr.Count() > 3)
.ToDictionary(
gr => gr.Key,
gr => gr.Count());
var output = repeatedWords.Concat(serialWords)
.OrderByDescending(kvp => kvp.Value) // Doesn't add much value, but oh well
.Select(kvp => kvp.Key);
Console.Write(string.Join(Environment.NewLine, output));
Prints:
AMB
MON
WATER
LUX
BR06
HAL
SPLASH
FIRE
PRIEST
BU01
MUM
LAVA
BIRDSONG
FALL
WALK1
WALK2
IDLE
JET
BIG
CAVES
EARTHQUAKE
SURPRISE

Matching Unicode characters in a regular expression

I retrieve strings from a website using the HttpClient class. The webserver sends them in UTF-8 encoding. The strings have the form abc | a and I'd like to remove the pipe, the space and the character after the space from them, if they are at the end of the string.
sText = Regex.Replace (sText, #"\| .$", "");
works as expected. Now, in some cases, the pipe and the space is followed by another character, for example a smiley. The string has then the form abc | 😉. The regular expression above does not work and I have to use
sText = Regex.Replace (sText, #"\| ..$", "");
instead (two dots).
I'm quite sure it has something to do with the encoding and with the fact that the smiley uses more bytes in UTF-8 than a latin character - and the fact that c# doesn't know the encoding. The smiley is just one character, even if it uses more bytes, so after telling c# the correct encoding (or converting the string), the first regular expression should work in both cases.
How can this be done?
Like it was suggested in the comments, this problem is hard to solve using Regex. What you call "looks like one item" is actually a grapheme cluster. The corresponding .NET term is a "text element" that can be parsed and iterated through using StringInfo.GetTextElementEnumerator.
A possible solution based on text elements can be quite simple: we just need to extract the last 3 text elements from the input string and ensure that they refer to a pipe, a space and the last one can be any. Please find below the proposed approach implementation.
void Main()
{
var inputs = new[] {
"abc | a",
"abc | ab", // The only that shouldn't be trimmed
"abc | 😉",
"abc | " + "\uD83D\uDD75\u200D\u2642\uFE0F" // "man-detective" (on Windows)
};
foreach (var input in inputs)
{
var res = TrimTrailingTextElement(input);
Console.WriteLine("Input : " + input);
Console.WriteLine("Result: " + res);
Console.WriteLine();
}
}
string TrimTrailingTextElement(string input)
{
// A circular buffer for storing the last 3 text elements
var lastThreeElementIdxs = new int[3] { -1, -1, -1 };
// Get enumerator of text elements in the input string
var enumerator = StringInfo.GetTextElementEnumerator(input);
// Iterate through the enitre input string,
// at each step save to the buffer the current element index
var i = -1;
while (enumerator.MoveNext())
{
i = (i + 1) % 3;
lastThreeElementIdxs[i] = enumerator.ElementIndex;
}
// The buffer index must be positive for a non-empty input
if (i >= 0)
{
// Extract indexes of the last 3 elements
// from the circular buffer
var i1 = lastThreeElementIdxs[(i + 1) % 3];
var i2 = lastThreeElementIdxs[(i + 2) % 3];
var i3 = lastThreeElementIdxs[i];
if (i1 >= 0 && i2 >= 0 && i3 >= 0 && // All 3 indexes must be initialized
i3 - i2 == 1 && i2 - i1 == 1 && // The 1 and 2 elements must be 1 char long
input[i1] == '|' && // The 1 element must be a pipe
input[i2] == ' ') // The 2 element must be a space
{
return input.Substring(0, i1);
}
}
return input;
}

How to export a generic MATLAB matrix to a text file, formatted like C# array

I have a matrix in MATLAB, like this:
[ 1 2 3 4; 5 6 7 8; 9 10 11 12]
I want to export it to a text file, in C# format:
double[,] myMat = { {1,2,3,4}, {5,6,7,8}, {9,10,11,12} };
I need a MATLAB function, called for example exportMatrix(), with two arguments:
the MATLAB matrix
the tipo in which this matrix must be exported
Two examples of how to use this function are the following:
exportMatrix( myMatrix1, 'short');
exportMatrix( myMatrix2, 'float');
I need also that if the matrix is multidimensional, the function should export it correctly. For example, if:
>> size(A)
ans =
100 10 3
then the result of calling exportMatrix( A, 'double'); should be:
double[, ,] A = {...};
That was a fun question :) Here is a starting point:
function exportMatrix(A)
% get dimensions
dimensions = size(A);
N_dim = length(dimensions);
% print variable declaration to console
fprintf('double[')
for i = 1:N_dim-1
fprintf(',')
end
% finish declaration and print rows of matrix
fprintf('] A= {%s}\n', exportRow(A, dimensions))
function str_out = exportRow(B, dims)
% recursively print matrix
% init output string
str_out = '';
% have we finished yet?
if length(dims) > 1
% if not, then go to next layer
for i=1:dims(1)
% this test is just to make sure that we do not reshape a
% one-dimensional array
if length(dims) > 2
% print next slice inside curly-braces
str_out = sprintf('%s{ %s },', str_out, exportRow(reshape(B(i,:), dims(2:end)), dims(2:end)) );
elseif length(dims) == 2
% we are almost at the end, so do not use reshape, but stil
% print in curly braces
str_out = sprintf('%s{ %s },', str_out, exportRow(B(i,:), dims(2:end)) );
end
end
else
% we have found one of the final layers, so print numbers
str_out = sprintf('%f, ', B);
% strip last space and comma
str_out = str_out(1:end-2);
end
% strip final comma and return
str_out = sprintf('%s', str_out(1:end-1));
which only works for 2D arrays and upwards. Try eg.
exportMatrix(rand(2,2,2))
you need to alter the fprintf statements if you want to print to a file...

Issue with LINQ

I created LINQ implementation of mod10 algorithm.
The source code:
string number = "7992739871";
int mod10sum = number.Reverse()
.Select((c, i) => (c - '0') << ((i + 1) & 1)) // Double every other digit and sum the digits of the products (e.g., 10: 1 + 0 = 1, 14: 1 + 4 = 5)
.Sum(c => c - '0') % 10; // together with the undoubled digits from the original number
string checkDigit = (mod10sum == 0 ? 0 : 10 - mod10sum).ToString("0");
Console.WriteLine(checkDigit);
As per the example, 7992739871 number should have check digit as 3; however, what I am getting is 15.
What I am doing wrong? I am sure the mistake is very small but can't find it.
The problem is with the Select method. In order to sum up all the digits (as described in the algorithm) you would need to return 1 and 0 instead of 10, 1 and 4 instead of 14 (as in your example).
The easiest (but it does not have to be the most optimal) way to do that is to conert number from Select to string (14 -> "14") and then split the string characters using SelectMany.
So your code should look as follows:
int mod10sum = number.Reverse()
.SelectMany((c, i) => ((c - '0') << ((i + 1) & 1)).ToString())
.Sum(c => c - '0') % 10;
checkDigit = (mod10sum == 0 ? 0 : 10 - mod10sum).ToString("0");
Console.WriteLine(checkDigit);
A bit of theory
LINQ SelectMany returns IEnumerable<>. When you return string (which is IEnumerable) then that's why SelectMany "splits" returned string into characters.
Microsoft has very nice page (101 LINQ Samples) with different LINQ samples which should help you out.
EDIT
I would also recommend working on that conversion from int to string. I was working on similar project literally yesterday and in my case that conversion is a bit problematic from performance point of view as we call that method millions of times. If you have to calculate lots of mod10's then it might be not the best solution.
I would change the Sum.
At this point, you don't have a sequence of characters, but the single-or-doubled-as-appropriate value for each original digit.
Thus, you don't need to be subtracting 0, you need to be calculating the digit sum of each of these integers, and (since you know they'll be small) you can do this as simply as
.Sum(i => (i % 10) + (i / 10))
giving
string number = "7992739871";
int mod10sum = number.Reverse()
.Select((c, i) => (c - '0') << ((i + 1) & 1))
.Sum(i => (i % 10) + (i / 10)) % 10;
This should be more effecient than calling ToString() and iterating over the result.

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 names. 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.

Categories