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
Related
I have one string that contains integers and strings, separated by a comma.
For example:
0, Link Alive,1, Link Dead,2, Link Weak,3, Wiznet 0 Dead,4, Wiznet 1 Dead,5, Wiznets Dead
I want to make an enum out of this string like this:
public enum myEnums {
Link Alive = 0,
Link Dead = 2,
Link Weak = 1,
Wiznet 0 Dead = 3,
Wiznet 1 Dead = 4,
Wiznets Dead = 5
}
I was thinking about changing the string into a char array. After that I loop through the char array.
If I detect an integer, I assign its value to a temporary integer value. If I detect a string, I assign its value to a temporary string. After this I'll assign the temporary integer and string to an enumerator.
Only thing is, I don't know how to deal with the comma and the equal sign.
Can someone show me how it's supposed to be done?
It sounds to me like what you really ought to be doing is creating a Dictionary<string,int> since unless you are going to generate code, you can't change an enum at runtime, it's constant.
Now looking at your string:
0, Link Alive,1, Link Dead,2, Link Weak,3, Wiznet 0 Dead,4, Wiznet 1 Dead,5, Wiznets Dead
It looks like you have a set of comma delimited values. So split on , and then each pair of values is an int and a string. Make that you dictionary.
So a simple way to do that might look like this (assuming your data is good, i.e. it has a even number of items and every odd item actually can be parsed as an int):
var dict = new Dictionary<int,string>();
var cells = source.Split(',');
for (var i=0; i < cells.Length; i+=2)
{
dict[int.Parse(cells[i])] = cells[i+1].Trim(); // Note: you might want to check boundaries first!
}
Or using Linq, you could do something like this:
string source = "0, Link Alive,1, Link Dead,2, Link Weak,3, Wiznet 0 Dead,4, Wiznet 1 Dead,5, Wiznets Dead";
var dict = source.Split(',')
.Select((v,i) => new { v, i })
.GroupBy(x => x.i/2)
.ToDictionary(x => int.Parse(x.First().v), x => x.Skip(1).First().v.Trim());
Here's a fiddle.
To explain what we are doing here:
First with Split your string on ,. This give us a string array with ["0","Link Alive","1","Link Dead",...]
Next we use Select to select each item and it's index in a pair. So now we have a collection of objects that looks something like [{v="0",i=0},{v="Link Alive",i=1},...]
Now we group this by dividing the index by 2. Because this is integer division, it will truncate. So 0/2 == 0 and 1/2 == 0 and 2/2 == 1 and 3/2 == 1. So we are sorting into pairs of values.
Finally we convert these groups (which we know are pairs of values) into a dictionary. To do that we use the first item in each group and parse it into an int and use that as the key for our dictionary. Then we use the second value as the value. This finally gives us our dictionary
Now with you dictionary, if you want to look up a value, it's easy:
var myValue = dict[2]; // myValue is now "Link Weak"
By enumerator I assume you mean something over which you can iterate. An 'enum' is basically a set of named integers.
So if you have a string of items separated by commas and want to 'iterate' over them, then this may help:
string input = "0, Link Alive,1, Link Dead,2, Link Weak,3, Wiznet 0 Dead,4, Wiznet 1 Dead,5, Wiznets Dead"
string[] parts = input.split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
foreach (string part in parts)
{
// do something
}
I'm working on reporting using rdlc where the report footer position needs to stay at bottom, but the four table footer visibility depend on certain condition.
For that I use Union and use Take(4) to make sure if any of the table footer is not visible it should be replaced with \r\n at the bottom.
Should be:
12345
\r\n
\r\n
\r\n
Not like this:
\r\n
\r\n
\r\n
12345
Here is my code.
var footerValues = new[]
{
salesOrder.Subtotal.ToString("N0"),
salesOrder.Discount.ToString("N0"),
salesOrder.PPN.ToString("N0"),
salesOrder.Total.ToString("N0")
};
var stats = new[] {
salesOrder.Discount >= 1 || salesOrder.PPN >= 1, // combined visibility
salesOrder.Discount >= 1, // visible only if the value >= 1
salesOrder.PPN >= 1, // visible only if the value >= 1
true // total always visible
};
var textValues = stats
.Select((v, i) => v ? footerValues[i] : null).OfType<string>()
.Union(Enumerable.Range(0, 4).Select(x => string.Empty).ToArray())
.Take(4)
.ToArray()
var footerValue = string.Join(Environment.NewLine, textValues);
If the stats produces
false, false, false, true
The expected footerValue would be
"12345\r\n\r\n\r\n\r\n"
But actual result is
"12345\r\n"
What's wrong with the code? Or can it be simplified?
This part:
.Union(Enumerable.Range(0, 4).Select(x => string.Empty).ToArray())
is pointless. it will only return one string.Empty. Because Union removes the duplicates. I think you want Concat instead.Btw, you can also replace Enumerable.Range with Enumerable.Repeat
var textValues = stats
.Select((v, i) => v ? footerValues[i] : null).OfType<string>()
.Concat(Enumerable.Repeat(string.Empty, 4))
.Take(4)
.ToArray();
I'm trying to get a list of string ordered such that the longest are on either end of the list and the shortest are in the middle. For example:
A
BB
CCC
DDDD
EEEEE
FFFFFF
would get sorted as:
FFFFFF
DDDD
BB
A
CCC
EEEEE
EDIT: To clarify, I was specifically looking for a LINQ implementation to achieve the desired results because I wasn't sure how/if it was possible to do using LINQ.
You could create two ordered groups, then order the first group descending(already done) and the second group ascending:
var strings = new List<string> {
"A",
"BB",
"CCC",
"DDDD",
"EEEEE",
"FFFFFF"};
var two = strings.OrderByDescending(str => str.Length)
.Select((str, index) => new { str, index })
.GroupBy(x => x.index % 2)
.ToList(); // two groups, ToList to prevent double execution in following query
List<string> ordered = two.First()
.Concat(two.Last().OrderBy(x => x.str.Length))
.Select(x => x.str)
.ToList();
Result:
[0] "FFFFFF" string
[1] "DDDD" string
[2] "BB" string
[3] "A" string
[4] "CCC" string
[5] "EEEEE" string
Don't ask how and why... ^^
list.Sort(); // In case the list is not already sorted.
var length = list.Count;
var result = Enumerable.Range(0, length)
.Select(i => length - 1 - 2 * i)
.Select(i => list[Math.Abs(i - (i >> 31))])
.ToList();
Okay, before I forget how it works, here you go.
A list with 6 items for example has to be reordered to this; the longest string is at index 5, the shortest one at index 0 of the presorted list.
5 3 1 0 2 4
We start with Enumerable.Range(0, length) yielding
0 1 2 3 4 5
then we apply i => length - 1 - 2 * i yielding
5 3 1 -1 -3 -5
and we have the non-negative part correct. Now note that i >> 31 is an arithmetic left shift and will copy the sign bit into all bits. Therefore non-negative numbers yield 0 while negative numbers yield -1. That in turn means subtracting i >> 31 will not change non-negative numbers but add 1 to negative numbers yielding
5 3 1 0 -2 -4
and now we finally apply Math.Abs() and get
5 3 1 0 2 4
which is the desired result. It works similarly for lists of odd length.
Just another option, which I find more readable and easy to follow:
You have an ordered list:
var strings = new List<string> {
"A",
"BB",
"CCC",
"DDDD",
"EEEEE",
"FFFFFF"};
Create a new list and simply alternate where you add items::
var new_list = new List<string>(); // This will hold your results
bool start = true; // Insert at head or tail
foreach (var s in strings)
{
if (start)
new_list.Insert(0,s);
else
new_list.Add(s);
start = !start; // Flip the insert location
}
Sweet and simple :)
As for Daniel Bruckner comment, if you care about which strings comes first, you could also change the start condition to:
// This will make sure the longest strings is first
bool start= strings.Count()%2 == 1;
I am currently trying to write a function that would help me find similarities between binary strings. This sounds vague so I will explain with an example.
StringA : 10111010000
StringB : 10111010011
StringC : 10111101111
I want my program to be able to find any similarities (4 digits or more) occuring at the same index. In the above example, my function would return : 0-4 (because caracters 0 to 4 are identical in all three strings).
I am not looking for code, just a logical and optimal way of doing this.
String is Array of Char.
You should do Loop in which you would compare each char.
For Example: (I had to put example, sorry)
for(int i=0;i<=length;i++) \\length = array lenght
{
if(StringA[i]==StringB[i]) CounterA++; \\or something like this
}
method 1: split the strings into either an Array, or a List, then use LINQ to find the groupings within the list...
method 2: loop through each string, then through each character, then create a new string with the character length, and compare to the same substring on the other strings...
Assuming all three items are stored in their own respective variables, I would split all of the bits into an array. From there, I would iterate through one array (since all of the arrays are the same size) and match from there. This operation would be O(n) since you have to look at n items.
Pseudocode?
array := array[numbers]
for each binary number
for each binary number
if numbers have the same binary digit at current index
array[index] := array[index] + 1
end
end
end
Iterate each character in the string, if they match add to a counter:
private static int GetDifferences(string firstStr, string secondStr)
{
int val = 0;
char[] first = firstStr.ToCharArray();
char[] second = secondStr.ToCharArray();
for (int i = 0; i < first.Length; i++)
{
if (first[i] == second[i])
{
val++;
}
}
return val;
}
By no means perfect but should get you started
i'd split them into a list:
static void Main()
{
var a = "10111010000";
var b = "10111010011";
var c = "10111101111";
var aList = Split(a, 4); //Use a custom split method
var bList = Split(b, 4);
var cList = Split(c, 4);
Dictionary<int,string> hits = new Dictionary<int, string>();
for (int i = 0; i < aList.Count(); i++)
{
if(aList[i] == bList[i] && bList[i] == cList[i])
hits.Add(i,aList[i]);
}
}
Probably you could use Bitwise operators:
get XOR result from A/B (say:A^B) and A/C (say:A^C)
get NOT result of step 1: ~(A^B); ~(A^C)
get And result from step 2: (~(A^B))&(~(A^C))
get the 1 part from step 3.
e.g.:
1.
A^B=10111010000^
10111010011
=00000000011;
A^C=10111010000^
10111101111
=00000111111
2.
~(A^B)=~(00000000011)=11111111100;
~(A^C)=~(00000111111)=11111000000;
3.
(~(A^B))&(~(A^C)) =11111111100&
11111000000
=11111000000
If you were just wanting to get a true or false as to whether there is a minimum of 4 matching characters, you could do this:
Public Function StringsHaveMin4CharsInCommon(ByVal StringA As String, ByVal StringB As String, ByVal StringC As String) As Boolean
Dim bReturn As Boolean
Dim iCounter As Integer
For i As Integer = 0 To StringA.Length - 1
If StringA.SubString(i, 1) = StringB.SubString(i, 1) And StringB.SubString(i, 1) = StringC.SubString(i, 1) Then iCounter += 1
If iCounter = 4 Then
bReturn = True
Exit For
End If
Next i
Return bReturn
End Function
If you wanted to retrieve the matching array indices then you would need to add logic to the same procedure to add each matching index to an Integer array and return that array from the function as follows.
Public Function GetCommonIndices(ByVal StringA As String, ByVal StringB As String, ByVal StringC As String) As Integer()
Dim iReturn() As Integer
Dim iCounter As Integer = -1
For i As Integer = 0 To StringA.Length - 1
If StringA.SubString(i, 1) = StringB.SubString(i, 1) And StringB.SubString(i, 1) = StringC.SubString(i, 1) Then
iCounter += 1
ReDim Preserve iReturn(iCounter)
iReturn(iCounter) = i
End If
Next i
Return iReturn
End Function
The function will return Nothing if there are no matching indices.
The functions only test for the length of StringA so it will throw an error if either StringB or StringC is shorter than String A. I inferred that the strings that you will be testing will be pre-validated as being all equal in length.
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)))