C# array from text files with specific values - c#

I have this file called failas.txt. It contains text in Lithuanian language. I did Encoding 1257 for it so it can read Lithuanian letters.
Now all I have to do is to make an array for each Lithuanian letter used in that file.
All those letters are in string p = "AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ";
Array should show how many times each letter is repeated in a text and write those results to a new txt file called rezultatai.txt. So the code is this:
using System;
using System.Linq;
using System.Globalization;
using System.Collections.Generic;
using System.Collections;
using System.IO; skirta biblioteka
using System.Text;
using System.Threading;
class Program
{
static void Main()
{
string failas = "failas.txt";
string rodymas = File.ReadAllText(failas, Encoding.GetEncoding(1257));
Console.OutputEncoding = Encoding.UTF8;
Console.WriteLine(rodymas);
char[] masyvas = rodymas.Where(Char.IsLetter).OrderBy(Char.ToLower).ToArray();
foreach (char c in masyvas)
{
Console.Write(c + ",");
}
string p = "AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ";
failas = failas.ToUpper();
Dictionary<char, int> dict = new Dictionary<char, int>();
foreach (char c in p) dict.Add(c, 0);
foreach (char c in failas)
{
int val;
if (dict.TryGetValue(c, out val)) dict[c] = val + 1;
}
//write to a file..
foreach (KeyValuePair<char, int> item in dict)
{
if (item.Value > 0) Console.WriteLine("Character {0}, No of Occurences = {1}", item.Key, item.Value);
File.AppendAllText("rezultatai.txt", item.Value + Environment.NewLine);
}
Console.WriteLine("Sum = {0}", dict.Sum(x => x.Value));
Console.ReadKey();
However, somehow it returns only output with letters A, F, I, L, S, T. Like this:
Character A, No of Occurences = 2
Character F, No of Occurences = 1
Character I, No of Occurences = 1
Character L, No of Occurences = 1
Character S, No of Occurences = 1
Character T, No of Occurences = 2
As I mentioned before, letters should be:
AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ
Also, when I open rezultatai.txt file to check appended values, it only contains a long column of numbers:
2
0
0
0
0
0
0
0
0
1
0
0
1
0
0
0
0
1
0
0
0
0
0
1
0
2
0
0
0
0
0
0
2
0
0
0
0
0
0
0
0
1
0
0
1
0
0
0
0
1
0
0
0
0
0
1
0
2
0

However, somehow it returns only output with letters A, F, I, L, S, T. Like this:
foreach (char c in failas)
You iterate over the filename, which is "failas.txt", This should be the actual file's text.
foreach (char c in rodymas)
foreach (char c in masyvas) // Possibly the char array.. not sure which..
Also, when I open rezultatai.txt file to check appended values, it only contains a long column of numbers:
Yes, you append the value from a KeyValuePair where the value is an integer, this presumably needs to be the same as what you output to the console.

.NET has pretty powerful features, like LINQ and the CultureInfo system. You can use both to do this in a few lines:
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
internal class Program
{
private static void Main()
{
var cultureLithunia = new CultureInfo("lt-LT");
var textInfoLithunia = cultureLithunia.TextInfo;
string requested = textInfoLithunia.ToUpper("AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ");
string content = File.ReadAllText("failas.txt", Encoding.GetEncoding(textInfoLithunia.ANSICodePage));
var characters = content.GroupBy(c => c);
var charactersYouWant = characters.Where(c => requested.Contains(textInfoLithunia.ToUpper(c.Key)));
var linesYouWantToOutput = charactersYouWant.Select(c => string.Format("Character {0}, No of Occurences = {1}", c.Key, c.Count()));
File.WriteAllLines("rezultatai.txt", linesYouWantToOutput);
Console.WriteLine("Done");
Console.ReadKey();
}
}
If you want all characters from the required text, it's a bit more complicated:
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
internal class Program
{
private static void Main()
{
var cultureLithunia = new CultureInfo("lt-LT");
var textInfoLithunia = cultureLithunia.TextInfo;
string requested = textInfoLithunia.ToUpper("AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ");
string content = File.ReadAllText("failas.txt", Encoding.GetEncoding(textInfoLithunia.ANSICodePage));
var characters = content.GroupBy(c => c);
var charactersYouWant = requested.Select(c => new { Key = c, Count = characters.Where(cc => textInfoLithunia.ToUpper(cc.Key) == c).Select(group => group.Count()).FirstOrDefault() });
var linesYouWantToOutput = charactersYouWant.Select(c => string.Format("Character {0}, No of Occurences = {1}", c.Key, c.Count));
File.WriteAllLines("rezultatai.txt", linesYouWantToOutput);
Console.WriteLine("Done");
Console.ReadKey();
}
}

Related

Convert String to Int in a Single Line C#

I have a string input like:
1 3 4 1 2
I want to Sum the number into integer. I tried the following code:
using System;
public class Program
{
public static void Main()
{
string input2 = "1 3 4 1 1";
string value2 = input2.Replace(" ", "+");
int val = int.Parse(value2);
Console.WriteLine(val);
}
}
But it is not correct. Does anyone have an idea for this?
Thank you.
You can try Split the initial string (input2) into items, TryParse them into corresponding int bvalues and then Sum them with a help of Linq:
using System.Linq;
...
int val = value2
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Sum(item => int.TryParse(item, out int value) ? value : 0);
Here all invalid items (i.e. items which can't be parsed as an integer) are ignored (we turn them into 0). You may want an exception thrown in this case:
using System.Linq;
...
int val = value2
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Sum(item => int.Parse(item));
Finally, your code amended (we can use an old trick with DataTable.Compute):
using System.Data;
...
string input2 = "1 3 4 1 1";
string formula = input2.Replace(' ', '+');
using (DataTable table = new DataTable())
{
int val = Convert.ToInt32(table.Compute(formula, null));
Console.WriteLine(val);
}
You can Split input2 with a space character into an array then use system.linq.enumerable.sum()
string input2 = "1 3 4 1 1";
var result= input2.Split(' ').Sum(x=> int.Parse(x));

Find and Count works but not the way I want

byte count = 0;
string word = "muumuu";
string res= word;
bool flg = true;
foreach(char ch in word)
{
res = res.Remove(0,1);
if(res.Contains(ch))
{
flg = false;
count ++;
Console.WriteLine($"there are {count} same chars : {ch}");
}
}
if(flg)
{
Console.WriteLine($"All chars are different in : {word} ");
}
The output is :
there are 1 same chars : m
there are 2 same chars : u
there are 3 same chars : u
there are 4 same chars : u
The question is how to count same chars like :
there are 2 same chars : m
there are 4 same chars : u
You have to separate the counting from the output of the result.
The following solution collects the character counts in a dictionary and after that displays the contents of the dictionary:
string word = "muumuu";
var counts = new Dictionary<char, int>();
foreach (var ch in word)
{
if (counts.ContainsKey(ch))
counts[ch]++;
else
counts[ch] = 1;
}
foreach (var chCount in counts)
{
Console.WriteLine($"{chCount.Value} occurrences of '{chCount.Key}'");
}
A very compact alternative solution using Linq GroupBy method:
string word = "muumuu";
foreach (var group in word.GroupBy(c => c))
{
Console.WriteLine($"{group.Count()} occurrences of '{group.Key}'");
}
GroupBy groups the characters in the word so that each distinct character creates a group and each group contains the collected identical characaters. These can then be counted using Count.
Result:
2 occurrences of 'm'
4 occurrences of 'u'
Klaus' answer might be easier to understand, but you can also use this function which does mostly the same thing:
public static int CountDuplicates(string str) =>
(from c in str.ToLower()
group c by c
into grp
where grp.Count() > 1
select grp.Key).Count();
Usage: var dupes = $"{word} - Duplicates: {CountDuplicates(word)}";

Linq return 2D array with index from string splitting

I have a folder with multiple files with format NameIndex.Index. I need a 2D array returned with Linq, where Name is my string and the two indices (both only 1 char) are the 2D array indices.
Example: Head4.2 will be in my returned array on the [4,2] position.
File[,] files = arrayWithAllFiles.Select(f => f.name.StartsWith(partName))
. // dont know how to continue
/*
result would look like, where the element is the File (not it's name):
| Head0.0 Head0.1 Head0.2 ... |
| Head1.0 Head1.1 Head1.2 ... |
*/
PS: could it be also done to check for indices bigger than 9?
You can use Regex to parse the file names, that way you don't have to worry about the numbers being bigger than 9. The numbers can have more than one digit.
For example,
using System.Text.RegularExpressions;
/*
Pattern below means - one or more non-digit characters, then one or more digits,
then a period, then one or more digits. Each segment inside the parentheses will be one
item in the split array.
*/
string pattern = #"^(\D+)(\d+)\.(\d+)$";
string name = "Head12.34";
var words = Regex.Split(name, pattern);
// Now words is an array of strings - ["Head", "12", "34"]
So for your example you could try:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
string pattern = #"^(\D+)(\d+)\.(\d+)$";
var indices = files.Select(f =>
Regex.Split(f.name, pattern).Skip(1).Select(w => System.Convert.ToInt32(w)).ToArray()).ToArray();
// Getting the max indices in each direction. This decides the dimensions of the array.
int iMax = indices.Select(p => p[0]).Max();
int jMax = indices.Select(p => p[1]).Max();
var pairs = Enumerable.Zip(indices, files, (index, file) => (index, file));
File[,] files = new File[iMax + 1, jMax + 1];
foreach (var pair in pairs){
files[pair.index[0], pair.index[1]] = pair.file;
}
I'm not much of a regex fan, thats why I suggest the following solution, assuming your input is valid:
private static (string name, int x, int y) ParseText(string text)
{
var splitIndex = text.IndexOf(text.First(x => x >= '0' && x <= '9'));
var name = text.Substring(0, splitIndex);
var position = text.Substring(splitIndex).Split('.').Select(int.Parse).ToArray();
return (name, position[0], position[1]);
}
private static string[,] Create2DArray((string name, int x, int y)[] items)
{
var array = new string[items.Max(i => i.x) + 1, items.Max(i => i.y) + 1];
foreach (var item in items)
array[item.x, item.y] = item.name;
return array;
}
Then you can call these functions like this:
var files = new[] { "head1.0", "head4.1", "head2.3" };
var arr = Create2DArray(files.Select(ParseText).ToArray());

Split String to array and Sort Array

I am trying to sort a string split by comma. But it is not behaving as expected
var classes = "10,7,8,9";
Console.Write(string.Join(",", classes.Split(',').OrderBy(x => x)));
Console.ReadKey();
and output is
10,7,8,9
But I want the expected output to be like:
7,8,9,10
Classes can have a section along with them. like 7a,7b
and I want to achieve it on one line of code.
You can use Regex like this
var classes = "10,7,8,9";
Regex number = new Regex(#"^\d+");
Console.Write(string.Join(",", classes.Split(',').OrderBy(x => Convert.ToInt32(number.Match(x).Value)).ThenBy(x => number.Replace(x, ""))));
Console.ReadKey();
CODE:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Collections;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
var l = new List<string> { "1D", "25B", "30A", "9C" };
l.Sort((b, a) =>
{
var x = int.Parse(Regex.Replace(a, "[^0-9]", ""));
var y = int.Parse(Regex.Replace(b, "[^0-9]", ""));
if (x != y) return y - x;
return -1 * string.Compare(a, b);
});
foreach (var item in l) Console.WriteLine(item);
}
}
}
OUTPUT:
1D
9C
25B
30A
ONLINE COMPILE:
http://rextester.com/CKKQK66159
Use the following using-directive:
using System.Text.RegularExpressions;
And try the following:
var input = "7,7a,8,9a,9c,9d,10";
var sorted = from sp in input.Split(',')
let reg = Regex.Match(sp, #"(?<num>[0-9]+)(?<char>[a-z]*)", RegexOptions.IgnoreCase | RegexOptions.Compiled)
let number = int.Parse(reg.Groups["num"].ToString())
orderby reg.Groups["char"].ToString() ascending // sort first by letter
orderby number ascending // then by number
select sp;
var result = string.Join(",", sorted);
Console.WriteLine(result);
//output (tested): 7,7a,8,9a,9c,9d,10
It uses regex to determine the numeric and alphabetic part of the input string.
The regex pattern uses named groups, which are noted as follows: (?<group_name> regex_expr ).
The time complexity of the code above is O(n log(n)), in case you are worried about big collections of numbers.
More information about named Regex groups.
More information about LINQ.
... and about the orderby-clause.
All on one line, also supports '4a' etc.
edit: On testing this, a string such as 1,2,111,3 would display as 111,1,2,3, so may not quite be what you're looking for.
string str = "1,2,3,4a,4b,5,6,4c";
str.Split(',').OrderBy(x => x).ToList().ForEach(x=> Console.WriteLine(x));
Console.ReadKey();
Here is my implementation:
IEnumerable<Tuple<string, string[]>> splittedItems =
items.Select(i => new Tuple<string, string[]>(i, Regex.Split(i, "([0-9]+)")));
List<string> orderedItems = splittedItems.OrderBy(t => Convert.ToInt16(t.Item2[1]))
.ThenBy(t => t.Item2.Length > 1 ? t.Item2[2] : "1")
.Select(t => t.Item1).ToList();
Split the input to a number and non numeric characters
Store the splitted strings with their parent string
Order by number
Then order by non numeric characters
Take the parent string again after sorting
The result is like required: { "10", "7", "8b", "8a", "9" } is sorted to { "7", "8a", "8b", "9", "10" }
You are sorting strings (alphabetically), so yes, "10" comes before "7".
My solution converts "10,7b,8,7a,9b" to "7a,7b,8,9b,10" (first sort by the integer prefix, then by the substring itself).
Auxiliary method to parse the prefix of a string:
private static int IntPrefix(string s)
=> s
.TakeWhile(ch => ch >= '0' && ch <= '9')
.Aggregate(0, (a, c) => 10 * a + (c - '0'));
Sorting the substrings by the integer prefix then by the string itself:
classes.Split(',') // string[]
.Select(s => new { s, i = IntPrefix(s) }) // IEnumerable<{ s: string, i: int }>
.OrderBy(si => si.i) // IEnumerable<{ s: string, i: int }>
.ThenBy(si => si.s) // IEnumerable<{ s: string, i: int }>
.Select(si => si.s) // IEnumerable<string>
One liner (with string.Join):
var result = string.Join(",", classes.Split(',').Select(s => new {s, i = IntPrefix(s)}).OrderBy(si => si.i).ThenBy(si => si.s).Select(si => si.s));

How can I convert a text file into a list of int arrays

I have a text file containing the following content:
0 0 1 0 3
0 0 1 1 3
0 0 1 2 3
0 0 3 0 1
0 0 0 1 2 1 1
0 0 1 0 3
0 0 1 1 3
0 0 1 2 3
0 0 3 0 1
0 0 1 2 3
0 0 3 0 1
There are no spaces between the rows but there is a space between the numbers. I want to read these integers from a txt file and save in a list of int arrays in C#.
Let's say your string is called text, and contains "1 1 1 0 3 2 3" etc.
You declare a string array.
String[] numbers1=text.Split(" ");
Now declare your int array and convert each one to int.
int[] numbers2=new int[numbers.Length];
for(int i=0; i<numbers.Length; i++)
numbers2[i]=Convert.ToInt32(numbers1[i]);
And you're done.
This works for me:
var numbers =
System.IO.File
.ReadAllLines(#"C:\text.txt")
.Select(x => x.Split(' ')
.Select(y => int.Parse(y))
.ToArray())
.ToList();
I get this result:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace FileToIntList
{
class Program
{
static void Main(string[] args)
{
// Read the file as one string.
System.IO.StreamReader myFile =
new System.IO.StreamReader("C:\\Users\\M.M.S.I\\Desktop\\test.txt");
string myString = myFile.ReadToEnd();
myFile.Close();
// Display the file contents.
//Console.WriteLine(myString);
char rc = (char)10;
String[] listLines = myString.Split(rc);
List<List<int>> listArrays = new List<List<int>>();
for (int i = 0; i < listLines.Length; i++)
{
List<int> array = new List<int>();
String[] listInts = listLines[i].Split(' ');
for(int j=0;j<listInts.Length;j++)
{
if (listInts[j] != "\r")
{
array.Add(Convert.ToInt32(listInts[j]));
}
}
listArrays.Add(array);
}
foreach(List<int> array in listArrays){
foreach (int i in array)
{
Console.Write(i + " ");
}
Console.WriteLine();
}
Console.ReadLine();
}
}
}
var resultList = new List<int>();
File.ReadAllLines("filepath")
.ToList()
.ForEach((line) => {
var numbers = line.Split()
.Select(c => Convert.ToInt32(c));
resultList.AddRange(numbers);
});
using System.IO;
using System.Linq;
string filePath = #"D:\Path\To\The\File.txt";
List<int[]> listOfArrays =
File.ReadLines(path)
.Select(line => line.Split(' ').Select(s => int.Parse(s)).ToArray())
.ToList();
Since you mention that it is your first time programming in C#, this version may be easier to understand; the process is the same as the above:
using System.IO;
using System.Linq;
string filePath = #"D:\Path\To\The\File.txt";
IEnumerable<string> linesFromFile = File.ReadLines(path);
Func<string, int[]> convertStringToIntArray =
line => {
var stringArray = line.Split(' ');
var intSequence = stringArray.Select(s => int.Parse(s)); // or ....Select(Convert.ToInt32);
var intArray = intSequance.ToArray();
return intArray;
};
IEnumerable<int[]> sequenceOfIntArrays = linesFromFile.Select(convertStringToIntArray);
List<int[]> listOfInfArrays = sequenceOfIntArrays.ToList();

Categories

Resources