I have a text file as follows:
1 ... 3 4 2
2 ... 3 21 4
3 ... 6 4 21 15
4 ... 14 21 12
I want to edit these strings, so that numbers after dotted parts to be splitted corresponding to the first number of each string. For example,
1
2 1
3 1 2
4 1 2 3
...
21 3 4
How can I do this?
Note: I obtain the first number group from a text file and edit it string by string. After that, I have written edited strings to the text file. In light of this, sample part of my code to obtain the first number group is provided as below:
for (var i = 0; i < existingLines.Length; i++)
{
var split = existingLines[i].Split('\t');
var act = i - 1;
var sc1 = int.Parse(split[6]);
var sc2 = int.Parse(split[7]);
appendedLines.Add(string.Format("{0} {1} {2}", act, sc1, sc2));
}
This LINQ code should get you started
string path = "c:\\temp\\test.txt";
using (var sr = new StreamReader(path))
{
var lines = new List<IEnumerable<int>>();
while (!sr.EndOfStream)
{
lines.Add(sr.ReadLine().Split(new[] { '.', ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(x => int.Parse(x)));
}
foreach (var node in lines.SelectMany(x => x).Distinct().OrderBy(x => x))
{
var predecessors = lines.Where(x => x.Skip(1).Contains(node))
.Select(x => x.First())
.OrderBy(x => x);
Console.WriteLine(node + " " + string.Join(" ", predecessors));
}
}
Output
2 1
3 1 2
4 1 2 3
6 3
12 4
14 4
15 3
21 2 3 4
Related
I have two different text files and I have to find 10 longest words that are in both of them. I have to print the list of those words out and write the frequency - how many times they are repeated in those separate files. The problem I have with my current code is that it finds the words, but when it comes to frequency - it combines the frequency count. How can I change the code to know the frequency count for separate files?
Here is my code for finding words that are in both text files:
public static Dictionary<string, int> PopularWords(string data1, string data2, char[] punctuation)
{
string[] book1 = data1.Split(punctuation, StringSplitOptions.RemoveEmptyEntries);
string[] book2 = data2.Split(punctuation, StringSplitOptions.RemoveEmptyEntries);
Dictionary<string, int> matches = new Dictionary<string, int>();
for (int i = 0; i < book1.Length; i++)
{
if (matches.ContainsKey(book1[i]))
{
matches[book1[i]]++;
continue;
}
for (int j = 0; j < book2.Length; j++)
{
if (book1[i] == book2[j])
{
if (matches.ContainsKey(book1[i]))
{
matches[book1[i]]++;
} else
{
matches.Add(book1[i], 2);
}
}
}
}
return matches;
And here is my code for reading and printing:
public static void ProcessPopular(string data, string data1, string results)
{
char[] punctuation = { ' ', '.', ',', '!', '?', ':', ';', '(', ')', '\n' };
string lines = File.ReadAllText(data, Encoding.UTF8);
string lines2 = File.ReadAllText(data1, Encoding.UTF8);
var popular = PopularWords(lines, lines2, punctuation);
KeyValuePair<string, int>[] popularWords = popular.ToArray();
Array.Sort(popularWords, (x, y) => y.Key.Length.CompareTo(x.Key.Length));
using (var writerF = File.CreateText(results))
{
int foundWords = 0;
writerF.WriteLine("{0, -25} | {1, -35} | {2, -35}", "Longest words", "Frequency in 1 .txt file", "Frequency in 2 .txt file");
writerF.WriteLine(new string('-', 101));
// not finished
}
}
Here's my take on this:
public static Dictionary<string, Dictionary<string, int>> PopularWords(string data1, string data2, char[] punctuation)
{
string[] book1 = data1.Split(punctuation, StringSplitOptions.RemoveEmptyEntries);
string[] book2 = data2.Split(punctuation, StringSplitOptions.RemoveEmptyEntries);
return
Enumerable
.Concat(
book1.Select(x => (word: x, book: "book1")),
book2.Select(x => (word: x, book: "book2")))
.ToLookup(x => x.word, x => x.book)
.OrderByDescending(x => x.Key.Length)
.Take(10)
.ToDictionary(x => x.Key, x => x.GroupBy(y => y).ToDictionary(y => y.Key, y => y.Count())); ;
}
If I start with this data:
char[] punctuation = new char[] { ' ', ',', '.', '?', '-', ':' };
string data1 = "I have two different text files and I have to find 10 longest words that are in both of them. I have to print the list of those words out and write the frequency - how many times they are repeated in those separate files. The problem I have with my current code is that it finds the words, but when it comes to frequency - it combines the frequency count. How can I change the code to know the frequency count for separate files?";
string data2 = "This solution is more general: it works whatever number of files you wish to process. This is an extremely raw query that could be separated in smaller queries, but it gives the logical basis. Other requirements, like only 10 words or minimum word length etc can be easily applied. Please do mind that this a bare-bone example, without any safety checks. It also omits reading data from files. The problem I have with my current code is that it finds the words, but when it comes to frequency - it combines the frequency count. How can I change the code to know the frequency count for separate files?";
I get this result:
"requirements": { "book2" = 1 }
"different": { "book1" = 1 }
"frequency": { "book1" = 4, "book2" = 3 }
"extremely": { "book2" = 1 }
"separated": { "book2" = 1 }
"repeated": { "book1" = 1 }
"separate": { "book1" = 2, "book2" = 1 }
"combines": { "book1" = 1, "book2" = 1 }
"solution": { "book2" = 1 }
"whatever": { "book2" = 1 }
To simplify, if performance is not the key here, I would go this way:
public static void Method()
{
var a = "A deep blue raffle, very deep and blue, raffle raffle. An old one was there";
var b = "deep blue raffle, very very very long and blue, raffle RAFFLE. A new one was there";
char[] punctuation = { '.', ',', '!', '?', ':', ';', '(', ')', '\n' };
var fileOne = new string(a.Where(c => punctuation.Contains(c) is false).ToArray()).Split(" ");
var fileTwo = new string(b.Where(c => punctuation.Contains(c) is false).ToArray()).Split(" ");
var duplicates = fileOne.Intersect(fileTwo, StringComparer.OrdinalIgnoreCase);
var result = new List<(int, int, string)>(duplicates.Count());
foreach(var duplicat in duplicates)
{
result.Add((fileOne.Count(x => x.Equals(duplicat, StringComparison.OrdinalIgnoreCase)), fileTwo.Count(x => x.Equals(duplicat, StringComparison.OrdinalIgnoreCase)), duplicat));
}
foreach (var val in result)
{
Output.WriteLine($"Word: {val.Item3} | In file one: {val.Item1} | In file two: {val.Item2}");
}
}
This will give you the result of
Word: A | In file one: 1 | In file two: 1
Word: deep | In file one: 2 | In file two: 1
Word: blue | In file one: 2 | In file two: 2
Word: raffle | In file one: 3 | In file two: 3
Word: very | In file one: 1 | In file two: 3
Word: and | In file one: 1 | In file two: 1
Word: one | In file one: 1 | In file two: 1
Word: was | In file one: 1 | In file two: 1
Word: there | In file one: 1 | In file two: 1
Other requirements, like only 10 words or minimum word length etc can be easily applied.
Please do mind that this a bare-bone example, without any safety checks. It also omits reading data from files.
EDIT I was not very pleased with my original solution, so I reworked it. I abandonned one thing I liked in my previous solution: the fact that it didn't depend on an external list of punctuation characters, but that this list was generated by the query itself. But it made the query more complicated and long.
In case you would be curious about a different coding style, here is a solution using Linq.
This solution is more general: it works whatever number of files you wish to process.
This is a Linqpad query that you can run directly via copy/paste, but you need to provide the text files of course:
// Choose here how many different words you want.
var resultCount = 10;
// Add as many files as needed.
var Files = new List<string>
{
#"C:\Temp\FileA.txt",
#"C:\Temp\FileB.txt",
#"C:\Temp\FileC.txt",
};
char[] punctuation = { '.', ',', '!', '?', ':', ';', '(', ')', '\n', '"', ' ' };
// Perform the calculation.
var LongestCommonWords = Files
.SelectMany(f => File.ReadAllText(f)
.Split(punctuation, StringSplitOptions.TrimEntries)
.ToLookup(w => ( word: w.ToLower(), fileName: f))
)
.ToLookup(e => e.Key.word)
.Where(g => g.Count() == Files.Count())
.OrderByDescending(g => g.Key.Length)
.Take(resultCount); // Take only the desired amount (10 for instance)
// Display the results.
foreach (var word in LongestCommonWords)
{
var occurences = string.Join(" / ", word.Select(g => $"{Path.GetFileName(g.Key.fileName)} - {g.Count()}"));
Console.WriteLine($"{word.Key} - {occurences}");
}
Here is an output obtained with the content of three Wikipedia pages:
contribution - FileA.txt - 9 / FileB.txt - 1 / FileC.txt - 5
subsequently - FileA.txt - 2 / FileB.txt - 1 / FileC.txt - 1
introduction - FileA.txt - 1 / FileB.txt - 4 / FileC.txt - 3
alternative - FileA.txt - 2 / FileB.txt - 1 / FileC.txt - 1
independent - FileA.txt - 5 / FileB.txt - 3 / FileC.txt - 3
significant - FileA.txt - 2 / FileB.txt - 1 / FileC.txt - 3
established - FileA.txt - 1 / FileB.txt - 1 / FileC.txt - 1
outstanding - FileA.txt - 1 / FileB.txt - 3 / FileC.txt - 3
programming - FileA.txt - 1 / FileB.txt - 2 / FileC.txt - 4
university - FileA.txt - 44 / FileB.txt - 17 / FileC.txt - 7
I don't understand the order of execution in the following code. Here the numbers that satisfied the first Where clause are (4, 10, 3, 7), and the numbers that satisfied the second Where clause are 2 and 1, after that we have function Aggregate that subtract them and make one element from both.
My question is what is the flow of execution here - (1) Where is executed with c/3 > 0 for all the elements and after that (2) Where or (1) first clause is executed for one element and its passed to (2) and from there to aggregate - when I print the values I cannot get value of x to be 28 on paper with both approaches also I cannot debug linq statement. Thanks for any help in advance.
var ints = new int[] { 2, 4, 1, 10, 3, 7 };
var x = ints
.Where(c => c / 3 > 0) <-- (1)
.Select(s2 => s2 + ints
.Where(c => c / 3 == 0) <-- (2)
.Aggregate((f, s) => f - s))
.Sum();
The same statement can be written as follows:
var ints = new int[] { 2, 4, 1, 10, 3, 7 };
var x = ints
.Where(c =>
{
Console.WriteLine($"1 Where for number: {c}");
return c / 3 > 0;
}) //< --(1)
.Select(s2 => s2 + ints
.Where(c =>
{
Console.WriteLine($"2 Where for number: {c}");
return c / 3 == 0;
}) // < --(2)
.Aggregate((f, s) =>
{
Console.WriteLine($"Aggregate: f: {f} s: {s}");
return f - s;
}))
.Sum();
In this every shorthand lambda expression can be written as a complete anonymous method with a method body. You just need to use the { .. } parentheses. Inside them you can write multiple statements. If you check the documentation for Where you can see that it expects (in your case) a Func<int, bool> as input parameter. That means that you pass an int inside and return a bool. This is why you need to write the explicit return statement as I did: return c / 3 > 0;
If you now insert there a debug output to the console you will get a written proof and insight into the execution of the entire code compartment.
The resulting output looks like the following:
1 Where for number: 2
1 Where for number: 4
2 Where for number: 2
2 Where for number: 4
2 Where for number: 1
Aggregate: f: 2 s: 1
2 Where for number: 10
2 Where for number: 3
2 Where for number: 7
1 Where for number: 1
1 Where for number: 10
2 Where for number: 2
2 Where for number: 4
2 Where for number: 1
Aggregate: f: 2 s: 1
2 Where for number: 10
2 Where for number: 3
2 Where for number: 7
1 Where for number: 3
2 Where for number: 2
2 Where for number: 4
2 Where for number: 1
Aggregate: f: 2 s: 1
2 Where for number: 10
....
....
ints
.Where(c => c / 3 == 0) // (2,1)
.Aggregate((f, s) => f - s) // 2-1
evaluates to 1
Therefore your query can be switched to:
var ints = new int[] { 2, 4, 1, 10, 3, 7 };
var x = ints
.Where(c => c / 3 > 0) // (4,10,3,7)
.Select(s2 => s2 + 1) // (5,11,4,8)
.Sum(); // 28
I am not sure if I am in the correct area on stack - so my apologies first ..
I need to know how I can calculate all possible combinations (for 3 different fixed lengths) that can fit into a Rod of n length.
So for example if I have 3 fixed lengths of 8, 10, 12 and a Rod of variable Length n say 50'; I want to know all the possible cuts that I can make.
Using Microsoft Solver Foundation:
const int rodLength = 50;
const int lengthA = 8, lengthB = 10, lengthC = 12;
var solver = SolverContext.GetContext();
var model = solver.CreateModel();
var decisionA = new Decision(Domain.IntegerNonnegative, "A");
model.AddDecision(decisionA);
var decisionB = new Decision(Domain.IntegerNonnegative, "B");
model.AddDecision(decisionB);
var decisionC = new Decision(Domain.IntegerNonnegative, "C");
model.AddDecision(decisionC);
model.AddGoal("Goal", GoalKind.Minimize,
rodLength - (decisionA * lengthA) - (decisionB * lengthB) - (decisionC * lengthC));
int maxItems = (rodLength / new [] { lengthA, lengthB, lengthC }.Min());
model.AddConstraint("MaxItems", decisionA + decisionB + decisionC < maxItems);
var solution = solver.Solve();
Console.WriteLine("A " + decisionA.GetDouble());
Console.WriteLine("B " + decisionB.GetDouble());
Console.WriteLine("C " + decisionC.GetDouble());
where we trying to minimize the difference between the rod length and the sum of the items constraining the number of items (in your case max 50 / 8 = 6 items).
Here is sample of code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication104
{
class Program
{
static void Main(string[] args)
{
string max = "111111";
int size = 50;
List<List<int>> numbers = CountModThree(max,size);
Print(numbers);
Console.ReadLine();
}
static List<List<int>> CountModThree(string max,int size)
{
List<List<int>> results = new List<List<int>>();
List<int> newMod3 = new List<int>() {0};
while(true)
{
int length = newMod3.Select(x => x == 0 ? 8 : x == 1 ? 10 : 12).Sum();
if (length <= size) results.Add(newMod3);
if (string.Join("", newMod3) == max) break;
newMod3 = AddOne(newMod3);
}
return results;
}
static List<int> AddOne(List<int> number)
{
List<int> newNumber = new List<int>();
newNumber.AddRange(number);
int carry = 1;
for (int i = number.Count - 1; i >= 0; i--)
{
int digit = newNumber[i] + carry;
if (digit == 3)
{
newNumber[i] = 0;
carry = 1;
}
else
{
newNumber[i] = digit;
carry = 0;
break;
}
}
if (carry == 1) newNumber.Insert(0, 0);
return newNumber;
}
static void Print(List<List<int>> numbers)
{
foreach(List<int> number in numbers)
{
Console.WriteLine("string : '{0}', Total Length : '{1}, Number 8ft sections : '{2}', Number 10ft sections : '{3}', Number 12ft sections : '{4}'",
string.Join("", number),
number.Select(x => x == 0 ? 8 : x == 1 ? 10 : 12).Sum(),
number.Where(x => x == 0).Count(),
number.Where(x => x == 1).Count(),
number.Where(x => x == 2).Count()
);
}
}
}
}
You want to get all partitions of n into predefined integer pieces. Simple approach is using recursion.
Python code gives all possible solutions, ignoring summands order due to last index usage. So 8 8 8 8 8 10 and 8 8 10 8 8 8 variants are considered the same. If you need to distinguish them, just remove last argument and start loop from 0.
def solution(sum, lst, last, sol):
if sum == 0:
print(sol)
return
for i in range(last, len(lst)):
if lst[i] <= sum:
solution(sum - lst[i], lst, i, sol + " " + str(lst[i]))
return
solution(50, [8,10,12], 0, "")
8 8 8 8 8 10
8 8 10 12 12
8 10 10 10 12
10 10 10 10 10
If you need also solutions with smaller overall length (if n is unreachable) - remember solutions with small rest of sum, then use ones with the smallest rest. Quick-made example:
dict = [[] for i in range(10)]
def solution(sum, lst, last, sol):
if sum == 0:
print(sol)
return
if sum < 10:
dict[sum].append(sol)
for i in range(last, len(lst)):
if lst[i] <= sum:
solution(sum - lst[i], lst, i, sol + " " + str(lst[i]))
return
solution(50, [5, 13 , 21], 0, "")
for i in range(1, len(dict)):
if len(dict[i]) > 0:
print(dict[i])
break
5 5 5 5 5 5 5 5 5 5 #exact
[' 5 5 5 13 21', ' 5 5 13 13 13'] #inexact but close
There is also non-recursive method: make table A[0..n] and fill it with items (note that table might be huge!)
def tablecuts(sum, lst):
cuts = [[] for i in range(sum+1)]
cuts[0].append('*')
for item in lst:
for i in range(0, sum - item + 1):
if len(cuts[i]) > 0:
for j in cuts[i]:
cuts[i+item].append(j+" " + str(item))
for i in range(len(cuts)):
print(i, cuts[i])
tablecuts(13, [2,5,7])
0 ['*']
1 []
2 ['* 2']
3 []
4 ['* 2 2']
5 ['* 5']
6 ['* 2 2 2']
7 ['* 2 5', '* 7']
8 ['* 2 2 2 2']
9 ['* 2 2 5', '* 2 7']
10 ['* 2 2 2 2 2', '* 5 5']
11 ['* 2 2 2 5', '* 2 2 7']
12 ['* 2 2 2 2 2 2', '* 2 5 5', '* 5 7']
13 ['* 2 2 2 2 5', '* 2 2 2 7']
I have a 2D array
var arr= new List<double[]>();
content:
1 2 3
4 3 7
7 8 9 10
11
I want to transpose it like a matrix to:
1 4 7 11
2 3 8
3 7 9
10
then move 10 to first like :
1 4 7 11
2 3 8
3 7 9
10
How do I do this in a efficient way?
Since we have to loop through all arrays 'vertically' anyway, I seriously doubt that it can be much more efficient then nested for's
You could find a longest array and use Linq .Where and .Select with overload that accepts index:
var arr = new List<double[]>();
arr.Add(new double[] { 1, 2, 3});
arr.Add(new double[] { 4, 3, 7 });
arr.Add(new double[] { 7, 8, 9, 10 });
arr.Add(new double[] { 11 });
var longestArr = arr.OrderByDescending(a => a.Length).First();
var result = longestArr.Select((_, i) => arr.Where(a => a.Length > i).Select(a => a[i]).ToArray()).ToList();
foreach (var _ in result)
{
foreach (var element in _)
{
Console.Write(element + " ");
}
Console.WriteLine();
}
Or do the same with good old for loop:
var longestArrLength = arr.Max(a => a.Length);
var result2 = new List<double[]>(arr.Count);
for (int i = 0; i < longestArrLength; i++)
{
result2.Add(arr.Where(a => a.Length > i).Select(a => a[i]).ToArray());
}
Output for both is:
1 4 7 11
2 3 8
3 7 9
10
Here is a DotNetFiddle
my Table data is"
ExpenseID PersonID SeqNumb HistorySeqNumb HistoryCode
1 3 1 1 9
2 1 1 1 9
3 2 1 1 0
4 1 2 1 0
5 1 1 2 0
6 5 1 1 0
7 3 1 2 0
ExpenseID is primary Key column .
If a record is inserted for a personID it has a sequence of 1 and History Code indicating 0 is active record.If the record is edited a new row is inserted with current row historyCode changed to 9 and new row History Code 0and history Sequence 2.
If another new record is inserted for the same person it has a new row with incremented sequence number.
My resultSet should contain the active records and the order the records were inserted:
I need lambda expression
Output should be
ExpenseID PersonID SeqNumb HistorySeqNumb HistoryCode
7 3 1 2 0
5 1 1 2 0
3 2 1 1 0
4 1 2 1 0
6 5 1 1 0
Your desired result seems wrong to me...
You only want active records, ok check
The order they were inserted...
3 > 4 > 5 > 6 > 7 not 7 > 5 > 3 > 4 > 6
In the top table Person ID was added again giving it an ExpenseID of 7 which is fine, it should be first (if you are sorting in descending). But then you have PersonID 1 with expense ID 5 when PersonID 5 with expense ID 6 was the previous record added before PersonID 3 with expense id 7
In short, your input data doesn't match your example desired output, making it rather difficult for anyone to answer you here.
From what I can see it looks like they should be sorted where HistoryCode = 0 Orderd By ExpenseID (bad database design comments aside)...
In such case it would be
var sortedItems = rawItems.Where(w => (w.HistoryCode == 0)).ToList();
sortedItems.Sort((emp1, emp2) => emp2.ExpenseID.CompareTo(emp1.ExpenseID));
//where rawItems is a List<Object> where object has properties for ExpenseID, PersonID... etc
Here is the entire Console App I made to experiment with this (bored), Add an Xml file called Data with the used Node/Attributes in it and set it to copy to output directory,
static void Main(string[] args)
{
var rawItems = new[] { new { ExpenseID = 0, PersonID = 0, SeqNumb = 0, HistorySeqNumb = 0, HistoryCode = 0 } }.ToList();
using (FileStream fs = new FileStream(Environment.CurrentDirectory + "\\data.xml", FileMode.Open, FileAccess.Read, FileShare.None))
{
XmlReader reader = XmlReader.Create(fs);
XDocument doc = XDocument.Load(reader);
fs.Flush();
doc.Root.Elements("Item").ToList().ForEach(i =>
{
var xExpenseID = Convert.ToInt32(i.Attribute("ExpenseID").Value);
var xPersonID = Convert.ToInt32(i.Attribute("PersonID").Value);
var xSeqNumb = Convert.ToInt32(i.Attribute("SeqNumb").Value);
var xHistorySeqNumb = Convert.ToInt32(i.Attribute("HistorySeqNumb").Value);
var xHistoryCode = Convert.ToInt32(i.Attribute("HistoryCode").Value);
rawItems.Add(new { ExpenseID = xExpenseID, PersonID = xPersonID, SeqNumb = xSeqNumb, HistorySeqNumb = xHistorySeqNumb, HistoryCode = xHistoryCode });
});
}
//sort
var sortedItems = rawItems.Where(w => (w.HistoryCode == 0)).ToList();
sortedItems.Sort((emp1, emp2) => emp2.ExpenseID.CompareTo(emp1.ExpenseID));
Console.Write("ExpenseID".PadRight(16, ' '));
Console.Write("PersonID".PadRight(16, ' '));
Console.Write("SeqNumb".PadRight(16, ' '));
Console.Write("HistorySeqNumb".PadRight(16, ' '));
Console.WriteLine("HistoryCode".PadRight(16, ' '));
foreach (var item in sortedItems)
{
Console.Write(item.ExpenseID.ToString().PadRight(16, ' '));
Console.Write(item.PersonID.ToString().PadRight(16, ' '));
Console.Write(item.SeqNumb.ToString().PadRight(16, ' '));
Console.Write(item.HistorySeqNumb.ToString().PadRight(16, ' '));
Console.WriteLine(item.HistoryCode.ToString().PadRight(16, ' '));
}
Console.ReadKey(true);
}