I have an array of tags that may appear in console as color tags. There's 37 of them.
So, I do this code:
tagsCT is a string[]
foreach (string tag in tagsCT)
{
if (text.Contains(tag))
{
ArrayList x = new ArrayList();
x.Add(tag);
x.Add(tagsColorValues[k]);
tagss.Add(text.IndexOf(tag));
tags.Add(text.IndexOf(tag) - 1, x);
}
k++;
}
What do I have:
text = "2013-11-11 17:56:14 [INFO] $4/time: $5Changes the time on each world"
What I need to do is find all the color tags in the string. All the possible ones are
in an array string[]
tagsCT = { "$1","$2","$3","$4" }
I show it as an example, but the tags aren't always the same length.
But the problem strikes in these situations:
text = "2013-11-11 17:56:14 [INFO] $4/time: $5Changes the time on each $4world"
The last tag will not be detected. The question is how to prevent it.
You could use a Dictionary<string, IList<int>> instead:
var tagIndices = new Dictionary<string, IList<int>>();
foreach (string tag in tagsCT)
{
IList<int> indices;
if (tagIndices.TryGetValue(tag, out indices))
continue; // to prevent the same indices on duplicate tags, you could also use a HashSet<string> instead of the array
else
{
indices = new List<int>();
tagIndices.Add(tag, indices);
}
int index = text.IndexOf(tag);
while (index >= 0)
{
indices.Add(index);
index = text.IndexOf(tag, index + 1);
}
}
Each tag is stored as key and the value is the list of indices (can be empty).
Here's a demonstration
How about, after you've processed the tag, remove it from the "text" string?
You could also use a for(int i;;i) structure using the IndexOf value.
(sorry, where the hell is he comment button then?)
Related
I want to trim all the white-spaces and empty strings only from the starting and ending of an array without converting it into a string in C#.
This is what I've done so far to solve my problem but I'm looking for a bit more efficient solution as I don't want to be stuck with a just works solution to the prob
static public string[] Trim(string[] arr)
{
List<string> TrimmedArray = new List<string>(arr);
foreach (string i in TrimmedArray.ToArray())
{
if (String.IsEmpty(i)) TrimmedArray.RemoveAt(TrimmedArray.IndexOf(i));
else break;
}
foreach (string i in TrimmedArray.ToArray().Reverse())
{
if (String.IsEmpty(i)) TrimmedArray.RemoveAt(TrimmedArray.IndexOf(i));
else break;
}
return TrimmedArray.ToArray();
}
NOTE: String.IsEmpty is a custom function which check whether a string was NULL, Empty or just a White-Space.
Your code allocates a lot of new arrays unnecessarily. When you instantiate a list from an array, the list creates a new backing array to store the items, and every time you call ToArray() on the resulting list, you're also allocating yet another copy.
The second problem is with TrimmedArray.RemoveAt(TrimmedArray.IndexOf(i)) - if the array contains multiple copies of the same string value in the middle as at the end, you might end up removing strings from the middle.
My advice would be split the problem into two distinct steps:
Find both boundary indices (the first and last non-empty strings in the array)
Copy only the relevant middle-section to a new array.
To locate the boundary indices you can use Array.FindIndex() and Array.FindLastIndex():
static public string[] Trim(string[] arr)
{
if(arr == null || arr.Length == 0)
// no need to search through nothing
return Array.Empty<string>();
// define predicate to test for non-empty strings
Predicate<string> IsNotEmpty = string s => !String.IsEmpty(str);
var firstIndex = Array.FindIndex(arr, IsNotEmpty);
if(firstIndex < 0)
// nothing to return if it's all whitespace anyway
return Array.Empty<string>();
var lastIndex = Array.FindLastIndex(arr, IsNotEmpty);
// calculate size of the relevant middle-section from the indices
var newArraySize = lastIndex - firstIndex + 1;
// create new array and copy items to it
var results = new string[newArraySize];
Array.Copy(arr, firstIndex, results, 0, newArraySize);
return results;
}
I like the answer by Mathias R. Jessen as it is efficient and clean.
Just thought I'd show how to do it using the List<> as in your original attempt:
static public string[] Trim(string[] arr)
{
List<string> TrimmedArray = new List<string>(arr);
while (TrimmedArray.Count>0 && String.IsEmpty(TrimmedArray[0]))
{
TrimmedArray.RemoveAt(0);
}
while (TrimmedArray.Count>0 && String.IsEmpty(TrimmedArray[TrimmedArray.Count - 1]))
{
TrimmedArray.RemoveAt(TrimmedArray.Count - 1);
}
return TrimmedArray.ToArray();
}
This is not as efficient as the other answer since the internal array within the List<> has to shift all its elements to the left each time an element is deleted from the front.
I'm trying to find how many elements are in my string array, so I can add to that array from the first empty element.
Here's what I've tried to do:
int arrayLength = 0;
string[] fullName = new string[50];
if (fullName.Length > 0)
{
arrayLength = fullName.Length - 1;
}
and then from that refer to the first available empty element as:
fullName[arrayLength] = "Test";
I can also use this to see if the array is full or not, but my problem is arrayLength is always equal to 49, so my code seems to be counting the size of the entire array, not the size of the elements that are not empty.
Cheers!
you can use this function to calculate the length of your array.
private int countArray(string[] arr)
{
int res = arr.Length;
foreach (string item in arr)
{
if (String.IsNullOrEmpty(item))
{
res -= 1;
}
}
return res;
}
EDIT : To find the first empty element
private int firstEmpty(string[] arr)
{
int res = 0;
foreach (string item in arr)
{
if (String.IsNullOrEmpty(item))
{
return res;
}
res++;
}
return -1; // Array is full
}
I'm trying to find how many elements are in my string array,
array.Length
so I can add to that array from the first empty element.
Array's don't have empty elements; there's always something in there, though it could be null.
You could find that by scanning through until you hit a null, or by keeping track each time you add a new element.
If you're going to add new elements then, use List<string> this has an Add() method that will do what you want for you, as well as resizing when needed and so on.
You can likely then just use the list for the next part of the task, but if you really need an array it has a ToArray() method which will give you one.
So if you want to use the array instead of a list you still simply can get the number of empty elements like this:
int numberOfEmptyElements = fullName.Count(x => String.IsNullOrEmpty(x));
Try the below code
string[] fullName = new string[50];
fullName[0] = "Rihana";
fullName[1] = "Ronaldo";
int result = fullName.Count(i => i != null);
in result you will have the number of occupied positions. In this case 2, cause 2 arrays are filled. From there you can count the empty. :)
In C# i using
using word = Microsoft.Office.Interop.Word;
For get a Synonym for words by using this code
var app = new word.Application();
var infosyn = app.SynonymInfo[Wtext[Op + 1].ToString(), word.WdLanguageID.wdArabic];
foreach (var item in infosyn.MeaningList as Array)
{
listBox1.Items.Add(item.ToString());
}
Image here
My Issue is i got only the meaning list ( What is red boxes in image), but i want all words like in the image ( words in red boxes and blue arrows, The whole list).
Note: i use Meaninglist, RelatedWordList and it's not working and make loops in loop take a each synonym words and check their synonyms. Like This
var apps = new words.Application();
var infosyns = apps.SynonymInfo[item.ToString(), words.WdLanguageID.wdArabic] ;
foreach (var iitem in infosyns.MeaningList as Array)
{
listBox1.Items.Add(iitem.ToString());
var appss = new wordss.Application();
var infosynss = appss.SynonymInfo[iitem.ToString(),wordss.WdLanguageID.wdArabic] ;
foreach (var iiitem in infosyns.MeaningList as Array)
{
listBox1.Items.Add(iiitem.ToString());
}
}
Image here
Oli4 is correct.
You need to loop through the underlying data by doing something like this:
foreach (var iiitem in infosyns.MeaningList as Array)
{
listBox1.Items.Add(iiitem.ToString());
foreach (var item in iiitem.MeaningList)
{
listBox1.Items.Add(item.ToString());
}
}
I had a similar problem, however by looping a predefined amount of times through the results, I got a lot more. This was just a quick code and I believe the efficiency could be improved, However I believe it will get you on the right track. (It is somewhat similar to what you have done.
private static string[] getAllMeanings(Application wordApp, string word, int maxSize = 12,bool addOriginal = false)
{
List<string> stringArr = new List<string>();
if (addOriginal)stringArr.Add(word);
SynonymInfo theSynonyms = wordApp.SynonymInfo[word];
foreach (var Meaning in theSynonyms.MeaningList as Array)
{
if (stringArr.Contains(Meaning) == false) stringArr.Add((string)Meaning);
}
for (int ii = 0; ii < stringArr.Count; ii++)
{
theSynonyms = wordApp.SynonymInfo[stringArr[ii]];
foreach (string Meaning in theSynonyms.MeaningList as Array)
{
if (stringArr.Contains(Meaning)) continue;
stringArr.Add(Meaning);
}
if (stringArr.Count >= maxSize) return stringArr.ToArray();
}
return stringArr.ToArray();
}
Basically this function gets all the related words and then recursively adds the related word and finds their related words. This ends up by very closely resembling your result if you set the maxSize to 15;
Note: maxSize is to stop the function, for instance the word "have" has at least 3600 'synonyms'. And optimally your result should remain relevant.
I have a file containing scores in the following format:
000001,1
000002,2
000012,1
232124,1
I build an array containing the score as the first element and the difficulty as the second element. I then add the array to the list like this:
// load highscores
public void LoadScores()
{
StreamReader file = new StreamReader("highScores.txt");
// loop through each line in the file
while ((line = file.ReadLine()) != null)
{
// seperate the score from the difficulty
lineData = line.Split(',');
// add each line to the list
list.Add(lineData);
}
OrderScores();
}
Next I order the list using an IEnumerable:
IEnumerable<string[]> scoresDesNormal, scoresDesHard;
// order the list of highscores
protected void OrderScores()
{
// order the list by descending order with normal difficulty at the top
scoresDesNormal = list.OrderByDescending(ld => lineData[0]).Where(ld => lineData[1].Contains("1"));
// order the list by descending order with hard difficulty at the top
scoresDesHard = list.OrderByDescending(ld => lineData[0]).Where(ld => lineData[1].Contains("2")).Take(3);
}
Now I want to print the two IEnumerable lists to the screen using spriteBatch.DrawString(). How do I correctly iterate through the list elements and the arrays in side of them? I want to print out both elements of each array stored in the lists.
First of all, your question.
If you do know how to draw 1 string, and you want to draw 2 strings combined with a separator between them ",", simply do this:
...
string firstString = ...
string secondString = ...
string toBeDrawn = firstString + "," + secondString;
DrawThisFellah ( toBeDrawn );
...
So, you have a string[] ? No problem:
...
string[] currentElement = ...
string firstString = currentElement[0];
string secondString = currentElement[1];
// etc
...
Secondly, you don't need to add the leading zeros just for the alphabetical OrderByDescending to work. You could parse (and thus validate) the strings and store them in elements of type int[] instead of string[].
THIRD, and this might interest you !
It is dangerous to use LINQ without knowing you're using it.
Are you aware that your IEnumerable<string[]> are actually queries, right ?
One could say that your IEnumerable<string[]> objects are actually "CODE AS DATA".
They contain not the result for your OrderByDescending but rather the logic itself.
That means that if you have say, 3 string[] elements in your lineData:
{ "1", "122" }, { "3", "42" }, { "5", "162" }
and you call OrderScores, then you will notice the results when enumerating scoresDesNormal (for instance). The following code:
foreach (var element in scoresDesNormal)
Console.WriteLine("{0}, {1}", element[0], element[1]);
would print out to the console:
1, 122
5, 162
(because the 2nd element has no '1' characters on the second subelement)
but if you go on and modify the lineData collection either by inserting new elements or removing elements (should it be a List<string[]>) or simply by modifying the values of existing elements (should it be a primitive array), then you will observe new results when enumerating scoresDesNormal without calling OrderScores !
So for instance the following code's comments are true (given you have a List<string[]> lineData):
List<string[]> lineData = new List<string[]>(new[] {
new[] { "1", "122" }, // contains 1
new[] { "3", "42" }, // does not contain 1
new[] { "5", "162" } // contains 1
});
OrderScores();
foreach (var element in scoresDesNormal)
Console.WriteLine(element[1]);
// the previous foreach prints out
// 162
// 122
lineData[1][1] = "421"; // make the "42" in the list become "421"
foreach (var element in scoresDesNormal)
Console.WriteLine(element[1]);
// the previous foreach prints out - even though we haven't called OrderScores again
// 162
// 421
// 122
If i were you, i would do it like this,
If the user clicks or presses a button to view scores, open a method, like this one.
public void DisplayScores()
{
Rectangle[] PositionOfText = new Rectangle[scoresDesNormal];
for (int i = 0; i< scoresDesNormal.Count; i++)
{
PositionOfText = new Rectangle(xPos, yPos, Width, Height);
}
//do the same for the other difficulties, this sets the position of the texts.
import a fontbatch that you would like to use.
and in your draw method have something like this,
for (int i = 0; i< scoresDesNormal.Count; i++)
spritebatch.drawString(MyFontBatch, scoresDesNormal[i], PositionOfText, Color.//your preffered color.
Now i can understand that their may be errors in that, but i'm not a fluent c# programmer, But thats more or less what you can do
I'm trying to solve a simple algorithm a specific way where it takes the current row and adds it to the top most row. I know there are plenty of ways to solve this but currently I have a text file that gets read line by line. Each line is converted to an sbyte (there's a certain reason why I am using sbyte but it's irrelevant to my post and I won't mention it here) and added to a list. From there, the line is reversed and added to another list. Here's the code I have for that first part:
List<List<sbyte>> largeNumbers = new List<List<sbyte>>();
List<string> total = new List<string>();
string bigIntFile = #"C:\Users\Justin\Documents\BigNumbers.txt";
string result;
StreamReader streamReader = new StreamReader(bigIntFile);
while ((result = streamReader.ReadLine()) != null)
{
List<sbyte> largeNumber = new List<sbyte>();
for (int i = 0; i < result.Length; i++)
{
sbyte singleConvertedDigit = Convert.ToSByte(result.Substring(i, 1));
largeNumber.Add(singleConvertedDigit);
}
largeNumber.Reverse();
largeNumbers.Add(largeNumber);
}
From there, I want to use an empty list that stores strings which I will be using later for adding my numbers. However, I want to be able to add numbers to this new list named "total". The numbers I'll be adding to it are not all the same length and because so, I need to check if an index exists at a certain location, if it does I'll be adding the value I'm looking at to the number that resides in that index, if not, I need to create that index and set it's value to 0. In trying to do so, I keep getting an IndexOutOfRange exception (obviously because that index doesn't exist). :
foreach (var largeNumber in largeNumbers)
{
int totalIndex = 0;
foreach (var digit in largeNumber)
{
if (total.Count == 0)
{
total[totalIndex] = digit.ToString(); //Index out of Range exception occurs here
}
else
{
total[totalIndex] = (Convert.ToSByte(total[totalIndex]) + digit).ToString();
}
totalIndex ++;
}
}
I'm just at a loss. Any Ideas on how to check if that index exists; if it does not create it and set it's underlying value equal to 0? This is just a fun exercise for me but I am hitting a brick wall with this lovely index portion. I've tried to use SingleOrDefault as well as ElementAtOrDefault but they don't seem to be working so hot for me. Thanks in advance!
Depending on if your result is have small number of missing elements (i.e. have more than 50% elements missing) consider simply adding 0 to the list till you reach neccessary index. You may use list of nullable items (i.e. List<int?>) instead of regular values (List<int>) if you care if item is missing or not.
Something like (non-compiled...) sample:
// List<long> list; int index; long value
if (index >= list.Count)
{
list.AddRange(Enumerable.Repeat(0, index-list.Count+1);
}
list[index] = value;
If you have significant number of missing elements use Dictionary (or SortedDictionary) with (index, value) pairs.
Dictionary<int, long> items;
if (items.ContainsKey(index))
{
items[key] = value;
}
else
{
items.Add(index, value);
}