LINQ grouping and ordering doesn't work as expected - linq

My expected output is:
Extension: .txt -- CATS.TXT -- DOGS.TXT Extension: .pdf --
INFO.PDF -- TEST2.PDF Extension: .doc -- SUMMARY.DOC --
TEST1.DOC
Here are the functions.
public void TestGroupByFluentSyntax()
{
string[] files = new string[] { "test1.doc", "test2.pdf", "cats.txt", "dogs.txt", "info.pdf", "summary.doc" };
IEnumerable<IGrouping<string, string>> query = files.GroupBy(file => System.IO.Path.GetExtension(file), file => file.ToUpper())
.OrderBy(grouping => grouping.Key);
foreach(IGrouping<string, string> grouping in query)
{
Console.WriteLine("Extension: " + grouping.Key);
foreach (string fileName in grouping)
Console.WriteLine(" -- " + fileName);
}
}
public void TestGroupByFluentSyntax2()
{
string[] files = new string[] { "test1.doc", "test2.pdf", "cats.txt", "dogs.txt", "info.pdf", "summary.doc" };
IEnumerable<IGrouping<string, string>> query = files.OrderBy(file => file).GroupBy(file => System.IO.Path.GetExtension(file), file => file.ToUpper());
foreach (IGrouping<string, string> grouping in query)
{
Console.WriteLine("Extension: " + grouping.Key);
foreach (string fileName in grouping)
Console.WriteLine(" -- " + fileName);
}
}
If I order first, then group it works. But grouping & ordering doesn't. What am I missing on the function 'TestGroupByFluentSyntax()' where I group, then order?

You are not that far away. In TestGroupByFluentSyntax(), your output is:
Extension: .doc
-- TEST1.DOC
-- SUMMARY.DOC
Extension: .pdf
-- TEST2.PDF
-- INFO.PDF
Extension: .txt
-- CATS.TXT
-- DOGS.TXT
You group by the extension and sort on extension. So when you display, the extension is from doc, pdf and txt. But the file in each group is not sorted. You can achieve your desired output (by reversing the order of extension - use OrderByDescending as:
IEnumerable<IGrouping<string, string>> query
= files.GroupBy(file => System.IO.Path.GetExtension(file), file => file.ToUpper())
.OrderByDescending(grouping => grouping.Key);
And when you display (sort each group - use OrderBy), use:
foreach (string fileName in grouping.OrderBy(name => name))
Console.WriteLine(" -- " + fileName);
Here will be the output:
Extension: .txt
-- CATS.TXT
-- DOGS.TXT
Extension: .pdf
-- INFO.PDF
-- TEST2.PDF
Extension: .doc
-- SUMMARY.DOC
-- TEST1.DOC

This worked:
public void TestGroupByFluentSyntax()
{
Console.WriteLine("TestGroupByFluentSyntax");
string[] files = new string[] { "test1.doc", "test2.pdf", "cats.txt", "dogs.txt", "info.pdf", "summary.doc" };
IEnumerable<IGrouping<string, string>> query = files.GroupBy(file => System.IO.Path.GetExtension(file), file => file.ToUpper());
foreach (IGrouping<string, string> grouping in query)
{
Console.WriteLine("Extension: " + grouping.Key);
foreach (string fileName in grouping.OrderBy(name => name))
Console.WriteLine(" -- " + fileName);
}
}

Related

skipping Rows in a CSV file to a certain word C#

I am new to C# coding and I have really tried to find an answer in any forum. I am using CSVHelper to read a CSV file and I want to skip a certain number of lines from the beginning of the file to a certain word. Now my code gives the following error message:
System.ObjectDisposedException: "Cannot read from a closed TextReader." Help me please :
private void cmdLoad_Click(object sender, EventArgs e)
{
OpenFileDialog OFDReader = new OpenFileDialog()
{ };
if (OFDReader.ShowDialog() == DialogResult.OK)
{
txtbox.Text = OFDReader.FileName;
}
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = ";", // Set delimiter
HasHeaderRecord = true,
//ShouldSkipRecord = (row) => row.Record[0].Contains("Date/Time"),
};
using (var reader = new StreamReader(OFDReader.FileName))
using (var csv = new CsvReader(reader, config))
{
//search for Line to start reader
string record = "Date/Time";
while (csv.Read())
{
if (csv.Read().Equals(record))
{
csv.Read();
csv.ReadHeader();
break;
}
using (var dr = new CsvDataReader(csv))
{
var dt = new DataTable();
dt.Load(dr);
dataGridView1.DataSource = dt; // Set datagridview source to datatable
}
}
}
}
}
}
I believe you just need to break out of the while (csv.Read()) when you find the "Date/Time" text. The CsvReader will do the rest from there.
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = ";", // Set delimiter
HasHeaderRecord = true
};
using (var reader = new StreamReader(OFDReader.FileName))
using (var csv = new CsvReader(reader, config))
{
//search for Line to start reader
string record = "Date/Time";
while (csv.Read())
{
if (csv.Context.Parser.RawRecord.Trim() == record)
{
break;
}
}
using (var dr = new CsvDataReader(csv))
{
var dt = new DataTable();
dt.Load(dr);
dt.Dump();
}
}

Unzip a file in kotlin script [.kts]

I was toying with the idea of rewriting some existing bash scripts in kotlin script.
One of the scripts has a section that unzips all the files in a directory. In bash:
unzip *.zip
Is there a nice way to unzip a file(s) in kotlin script?
The easiest way is to just use exec unzip (assuming that the name of your zip file is stored in zipFileName variable):
ProcessBuilder()
.command("unzip", zipFileName)
.redirectError(ProcessBuilder.Redirect.INHERIT)
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
.start()
.waitFor()
The different approach, that is more portable (it will run on any OS and does not require unzip executable to be present), but somewhat less feature-full (it will not restore Unix permissions), is to do unzipping in code:
import java.io.File
import java.util.zip.ZipFile
ZipFile(zipFileName).use { zip ->
zip.entries().asSequence().forEach { entry ->
zip.getInputStream(entry).use { input ->
File(entry.name).outputStream().use { output ->
input.copyTo(output)
}
}
}
}
If you need to scan all *.zip file, then you can do it like this:
File(".").list { _, name -> name.endsWith(".zip") }?.forEach { zipFileName ->
// any of the above approaches
}
or like this:
import java.nio.file.*
Files.newDirectoryStream(Paths.get("."), "*.zip").forEach { path ->
val zipFileName = path.toString()
// any of the above approaches
}
this code is for unziping from Assets
1.for unzping first u need InputStream
2.put it in ZipInputStream
3.if directory is not exist u have to make by .mkdirs()
private val BUFFER_SIZE = 8192//2048;
private val SDPath = Environment.getExternalStorageDirectory().absolutePath
private val unzipPath = "$SDPath/temp/zipunzipFile/unzip/"
var count: Int
val buffer = ByteArray(BUFFER_SIZE)
val context: Context = this
val am = context.getAssets()
val stream = context.getAssets().open("raw.zip")
try {
ZipInputStream(stream).use { zis ->
var ze: ZipEntry
while (zis.nextEntry.also { ze = it } != null) {
var fileName = ze.name
fileName = fileName.substring(fileName.indexOf("/") + 1)
val file = File(unzipPath, fileName)
val dir = if (ze.isDirectory) file else file.getParentFile()
if (!dir.isDirectory() && !dir.mkdirs())
throw FileNotFoundException("Invalid path: " + dir.getAbsolutePath())
if (ze.isDirectory) continue
val fout = FileOutputStream(file)
try {
while ( zis.read(buffer).also { count = it } != -1)
fout.write(buffer, 0, count)
} finally {
val fout : FileOutputStream =openFileOutput(fileName, Context.MODE_PRIVATE)
fout.close()
}
}
for unziping from externalStorage:
private val sourceFile= "$SDPath/unzipFile/data/"
ZipInputStream zis = null;
try {
zis = new ZipInputStream(new BufferedInputStream(new
FileInputStream(sourceFile)));
ZipEntry ze;
int count;
byte[] buffer = new byte[BUFFER_SIZE];
while ((ze = zis.getNextEntry()) != null) {
String fileName = ze.getName();
fileName = fileName.substring(fileName.indexOf("/") + 1);
File file = new File(destinationFolder, fileName);
File dir = ze.isDirectory() ? file : file.getParentFile();
if (!dir.isDirectory() && !dir.mkdirs())
throw new FileNotFoundException("Invalid path: " +
dir.getAbsolutePath());
if (ze.isDirectory()) continue;
FileOutputStream fout = new FileOutputStream(file);
try {
while ((count = zis.read(buffer)) != -1)
fout.write(buffer, 0, count);
} finally {
fout.close();
}
}
} catch (IOException ioe) {
Log.d(TAG, ioe.getMessage());
return false;
} finally {
if (zis != null)
try {
zis.close();
} catch (IOException e) {
}
}
return true;

How to get list of all field names in ElasticSearch?

I've been trying to get all the field names in my ElasticSearch database dynamically so I can input them into a GUI drop down search box.
{
"odd": ["three", "five", "nine"],
"even": ["two", "four", "six"],
"prime": ["seven", "thirteen", "seventeen"]
}
Is there a way to obtain the field names : odd, even and prime
Such that I can enter them into a Jcombobox in the user interface?
In jquery...
//...Get data
var hits = body.hits.hits;
$.each(hits, function(index, value){
var sources = hits[index]._source;
$.each(sources, function(i, j){//i is the name of the field and j is the value
//Use data
});
});
GetMappingsResponse res = null; //Get entire mapping of elasticsearch
try {
res = client.admin().indices().getMappings(new GetMappingsRequest().indices("foo").types("bar")).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
ImmutableOpenMap<String, MappingMetaData> mapping = res.mappings().get("foo");
String[] FieldNames = new String[20];
String[] FieldNameArray;
for (ObjectObjectCursor<String, MappingMetaData> c : mapping) {
FieldNames[0] = c.value.source().toString(); //grabs and stores the mapping
}
String dirtyField = FieldNames[0];
List<String> badWords = Arrays.asList( "foo"); //here i parse the entire mapping to just obtain the field names
for ( String badWord : badWords ) { //filters the mapping so we can capture only the added metadata
dirtyField = dirtyField.replaceAll("" + badWord + "", "");
}
String cleanField = dirtyField.replaceAll("[^\\w\\s]"," ");
FieldNameArray = cleanField.split("\\s+"); //splits the string into an array of individual words
System.out.println("Updated Field Name Array");
return FieldNameArray;
It's pretty ugly, but this is how i ended up resolving the issue and grabbing just the field names.

using regex for an xml file in linq

I'm trying to write a query for an Xml file.
this is my input Xml file :
<logentry
revision="10034">
<date>2009-10-07T03:45:38.000000Z</date>
<paths>
<path
kind="file"
action="M">/trunk/org.eclipse.mylyn.tasks/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaRepositoryConnectorTest.java</path>
<path
kind="file"
action="M">/trunk/org.eclipse.mylyn.tasks/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/core/BugzillaRepositoryConnectorStandaloneTest.java</path>
</paths>
</logentry>
I'm trying to filter all the log between date 2006-05-01 and 2007-09-01. and my output it should be like this:
10034 2009-10-07 BugzillaRepositoryConnectorTest.java,BugzillaRepositoryConnectorStandaloneTest.java
it means for each specific revision number where is between date1 and date2 I want to have list of all files from tag . I used regular expression for separating the file name from the path.
this is my code:
using(System.IO.StreamWriter file1= new System.IO.StreamWriter( #"/home/datehistory"))
{XDocument log= XDocument.Load(#"/home/output.xml");
var selected= from logs in log.Descendants("logentry")
select new
{revno=logs.Attribute("revision").Value,
date=logs.Element("date").Value,
list1= {from files in logs.Element("paths").Element("path").Value
let match=Regex.Match(files,#"/([A-Za-z0-9\-]+.java)<",RegexOptions.IgnoreCase);
where match.Success
select new
{filename=match.Groups[1].Value }; }
???? "please help " where date between 2006-05-01 and 2007-09-01
};
foreach (var d in selected)
{
file1.Write(d.revno);
file1.Write("\t");
file1.Write(d.date);
file1.Write("\t");
foreach item in d.list1
{file1.write(item);
file1.write("\t"); }
file1.write("\n");
}
Have you considered a simpler approach? For example something like this:
var xml =
#"<logentry
revision='10034'>
<date>2009-10-07T03:45:38.000000Z</date>
<paths>
<path
kind='file'
action='M'>/trunk/org.eclipse.mylyn.tasks/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/BugzillaRepositoryConnectorTest.java</path>
<path
kind='file'
action='M'>/trunk/org.eclipse.mylyn.tasks/org.eclipse.mylyn.bugzilla.tests/src/org/eclipse/mylyn/bugzilla/tests/core/BugzillaRepositoryConnectorStandaloneTest.java</path>
</paths>
</logentry>";
XDocument log= XDocument.Parse(xml);
foreach (var entry in log.Descendants("logentry")) {
var date = DateTime.Parse(entry.Element("date").Value);
Console.WriteLine(date);
foreach (var path in entry.Descendants("path")) {
var idx = path.Value.LastIndexOf('/');
Console.Write(path.Value.Substring(idx + 1) + ", ");
}
Console.WriteLine();
}
}
This leaves a trailing ", " but it's just an example instead of writelines you could add the info to a struct or container and output it to a file like your original example.
Try this:
using System;
using System.IO;
using System.Xml.Linq;
using System.Linq;
using System.Text;
class Program
{
static void Main(string[] args)
{
var outputPath = "outputPath.log";
var xDoc = XDocument.Load("input.xml");
var sb = new StringBuilder();
xDoc.Descendants("logentry").Cast<XElement>()
.Where(e =>
{
var date = DateTime.Parse(e.Descendants("date")
.FirstOrDefault().Value);
return date >= new DateTime(2006, 5, 1) &&
date <= new DateTime(2007, 9, 1);
}).ToList().ForEach(e =>
{
var revision = e.Attribute("revision").Value;
var date = DateTime.Parse(e.Descendants("date")
.FirstOrDefault().Value).ToString("yyyy-MM-dd");
sb.Append(String.Format("{0}\t", revision));
sb.Append(String.Format("{0}\t", date));
e.Descendants("path")
.Where(p => Path.GetExtension(p.Value).ToLower() == ".java")
.ToList().ForEach(p =>
sb.Append(String.Format("{0},",
Path.GetFileName(p.Value))));
if (sb[sb.Length - 1] == ',')
sb.Length = sb.Length - 1;
sb.AppendLine();
});
File.WriteAllText(outputPath, sb.ToString());
}
}

Transforming T4 from command line doesn't add generated files to csproj

I am trying to transform a T4 template from command line using TextTransform.exe with the following command line:
"%ProgramFiles(x86)%\Common Files\Microsoft Shared\TextTemplating\10.0\TextTransform.exe"
-out .\MyProj\MyT4.cs
-I "%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes"
-a !NamespaceHint!MyNameSpace
-dp T4VSHost!Microsoft.Data.Entity.Design.VisualStudio.Directives.FallbackT4VSHostProcessor!"%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\Microsoft.Data.Entity.Design.dll"
.\MyProj\MyT4.tt
Results:
No error messages
The %ERRORLEVEL% is 0 on completion.
The files are generated
The .csproj does not change
The problem is point 4. This may be expected, since the .csproj isn't a part of the above command line, however, I can't find any parameters which can accept it.
What am I doing wrong or what should I be doing instead?
P.S. When I use the button in Visual Studio the process works as excepted (new files are added to project).
Solved using the following method:
Added these parameters to command line:
-a !!ProjPath!.\MyProj\MyProj.csproj -a !!T4Path!.\MyProj\MyT4.tt
Changed the include directory parameter to a local path:
-I ".\Dependencies"
Copied EF.Utility.CS.ttinclude to that path and made the following changes:
3.1. Replaced:
public static EntityFrameworkTemplateFileManager Create(object textTransformation)
{
DynamicTextTransformation transformation = DynamicTextTransformation.Create(textTransformation);
IDynamicHost host = transformation.Host;
#if !PREPROCESSED_TEMPLATE
if (host.AsIServiceProvider() != null)
{
return new VsEntityFrameworkTemplateFileManager(transformation);
}
#endif
return new EntityFrameworkTemplateFileManager(transformation);
}
with
public static EntityFrameworkTemplateFileManager Create(object textTransformation)
{
DynamicTextTransformation transformation = DynamicTextTransformation.Create(textTransformation);
IDynamicHost host = transformation.Host;
#if !PREPROCESSED_TEMPLATE
if (host.AsIServiceProvider() != null)
{
return new VsEntityFrameworkTemplateFileManager(transformation);
}
#endif
return new EFTemplateFileManagerPlus(transformation);
}
(Last return has the change)
Add added this class to the file:
private sealed class EFTemplateFileManagerPlus : EntityFrameworkTemplateFileManager
{
private Action<IEnumerable<string>> projectSyncAction;
private readonly string _projPath;
private readonly string _t4Name;
public EFTemplateFileManagerPlus(object textTemplating)
: base(textTemplating)
{
var projPath = _textTransformation.Host.ResolveParameterValue("", "", "ProjPath");
var t4Path = _textTransformation.Host.ResolveParameterValue("", "", "T4Path");
_projPath = System.IO.Path.GetFullPath(projPath);
_t4Name = System.IO.Path.GetFileName(t4Path);
projectSyncAction = files => SyncCsProjFile(_projPath, _t4Name, files);
}
public static void SyncCsProjFile(string csProjFilePath, string t4FileName, IEnumerable<string> files)
{
files = files.Select(f => System.IO.Path.GetFileName(f)).Distinct().ToList();
var csProjDocument = new XmlDocument();
csProjDocument.Load(csProjFilePath);
var root = csProjDocument.DocumentElement;
XmlElement itemGroup = root.ChildNodes.OfType<XmlElement>()
.Where(n => n.Name == "ItemGroup")
.SelectMany(n => n.ChildNodes.OfType<XmlNode>()
.Where(c => c.Name == "Compile")
)
.Select(c => c.ParentNode)
.FirstOrDefault() as XmlElement;
if (itemGroup == null)
{
itemGroup = csProjDocument.CreateNode(XmlNodeType.Element, "ItemGroup", null) as XmlElement;
root.AppendChild(itemGroup);
}
var codeFiles = itemGroup.ChildNodes.OfType<XmlElement>()
.Where(c =>
c.Name == "Compile"
&& c.HasAttribute("Include") && !String.IsNullOrEmpty(c.GetAttribute("Include")))
.ToList();
var dependantFiles = codeFiles
.Where(f =>
f.ChildNodes.OfType<XmlElement>().Any(c =>
c.Name == "DependentUpon"
&& c.InnerText == t4FileName)
).ToList();
// Remove redundant files
foreach (var node in dependantFiles)
{
if (!files.Contains(node.GetAttribute("Include")))
itemGroup.RemoveChild(node);
}
// Add missing files
foreach (var name in files)
{
if (!dependantFiles.Any(node => node.GetAttribute("Include") == name))
{
var node = csProjDocument.CreateNode(XmlNodeType.Element, "Compile", null) as XmlElement;
node.SetAttribute("Include", name);
itemGroup.AppendChild(node);
var node2 = csProjDocument.CreateNode(XmlNodeType.Element, "DependentUpon", null) as XmlElement;
node2.InnerText = t4FileName;
node.AppendChild(node2);
}
}
SaveClean(csProjDocument, csProjFilePath);
}
static private void SaveClean(XmlDocument doc, string path)
{
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = true;
settings.IndentChars = " ";
settings.NewLineChars = "\r\n";
settings.NewLineHandling = NewLineHandling.Replace;
settings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
using (XmlWriter writer = XmlWriter.Create(sb, settings))
{
doc.Save(writer);
}
var newXml = sb.ToString().Replace("encoding=\"utf-16\"", "encoding=\"utf-8\"").Replace(" xmlns=\"\"", string.Empty);
System.IO.File.WriteAllText(path, newXml, Encoding.UTF8);
}
public override IEnumerable<string> Process(bool split)
{
var generatedFileNames = base.Process(split);
projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));
return generatedFileNames;
}
}
Now the project file sync works using TextTransform.exe too.
I believe the command line host cannot change the .csproj. Only the VS host can do it, through the access to the DTE object.

Resources