Groovy remove array element - gradle

i have this gradle task to get zip content and put it into another zip.
From src zip, i want to take all in directory 'r' and copy it into the target zip directory 'x/y/z'.
The code works, but I wonder if it can be more elegant.
from( zipTree("a.zip") ) {
include "r/**"
includeEmptyDirs = false
into "x/y/z"
eachFile { fcd ->
def segs1 = [fcd.relativePath.segments].flatten().findAll { it2 -> it2 != null };
segs1.removeAt(3)
fcd.relativePath = new RelativePath(true, segs1.toArray(new String[0]))
}
}
The problem I had is that fcd.relativePath.segments is String[], where i want to remove element with index 3.
Here i convert to list and back to array, brrr.
Ideas?
Frank

groovy based on java
and in java:
An array is a container object that holds a fixed number of values of a single type. The length of an array is established when the array is created. After creation, its length is fixed.
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
so, you could convert it to List, modify size, and then convert back to array
or create a new array with new size and copy required elements into it.

Related

Get the names of all the files/folders in an array

Basically I have a folder in that I have 4 zip files. I want to get the names of these zip files in an array.
Requirement :
I have a folder AggregatedComponetLibraries: I have my lib zips inside it. a.zip,b.zip,c.zip,d.zip. I want to get the name of the zips insde an array componentNames in gradle that means my array should contain : a,b,c,d
You can get it with FileTree so:
def names = []
fileTree(dir: 'AggregatedComponetLibraries', include: '**/*.zip').visit {
FileVisitDetails details ->
names << details.file.name
}
task printNames << {
println names
}
Here is the names array defined and then created a FileTree instance, for directory named "AggregatedComponetLibraries", this tree includes all the files with zip extention. After that, script traverses over the tree elements and add the element's names into the array.
Task printNames here is just to show the result.

Access variable hash depth values with square brackets notation

Given this hash:
hash1= { node1: { node2: { node3: { node4: { node5: 1 } } } } }
We access inside nodes with square brackets like this:
hash1[:node1][:node2][:node3][:node4]
Now I have a hash that I know will always be nested as it is an XML response from a SOAP webservice, but neither the depth of the hash nor the names of the nodes stay the same. So it would be nice if I could ask the user of my application for the hash depth and store it in a variable. And then be able to do hash1[:hash_depth] and achieve the same result as above.
I have accomplished what I want by the following code:
str = 'node1,node2,node3,node4'
str_a = str.split(',')
hash_copy = hash1
str_a.each { |s| hash_copy = hash_copy.[](s.to_sym) }
hash_copy
=> {:node5=>1}
hash1[:node1][:node2][:node3][:node4]
=> {:node5=>1}
that is asking the user to enter the hash depth separated by commas, store it in a string, split it, make an array, clone the original hash, go down each level and modify the hash till I get to the desired node. Is there a way to do it with the square brackets notation and using a variable to store the depth without modifying the hash or needing to clone it?
Edit:
someone answered with the following (can't see his post anymore???)
hash_depth="[:node1][:node2][:node3][:node4]"
eval "hash1#{hash_depth}"
Although eval does everything you need, there is another approach, since you already have the working code for comma-separated list:
hash_depth="[:node1][:node2][:node3][:node4]"
csh = hash_depth.gsub(/\A\[:|\]\[:|\]\Z/, { '][:' => ',' })
#⇒ "node1,node2,node3,node4"
And now you are free to apply your existing function to csh.
If this is a webapp, I think you should prepare a list of short textareas, which starts with a single text item, and the user can keep adding a new item to the list by clicking on a button. The areas will be filled by the user, and will be sent.
Then, you will probably receive this through some serialized form. You decode this to get an array of strings:
str_a = ["node1", "node2", "node3", "node4"]
and you can reach the inner element by doing:
str_a.inject(hash1){|h, s| h[s.to_sym]} #=> {:node5 => 1}

algorithm for regrouping data from flat file to hash with keys

I run into this fairly frequently. I have a batch of data (stored in CSV, XML, it doesn't matter) in some version of this format:
key1|value1
key1|value2
key1|value3
key2|value4
key2|value5
etc.
and need to be able to handle it in this form:
data[key1] => [value1, value2, value3]
data[key2] => [value4, value5]
etc.
What's the best approach to converting from A to B? I typically loop over the list like this (pseudocode), but I don't like that I have to repeat my array building code.
data = []
values = []
currentKey = ""
foreach (line in inputData) {
key, value = split(line)
if ((currentKey != "") and (currentKey != key)) {
data[currentKey] = values
values = []
}
currentKey = key
values.add(value)
}
// this is the part I don't like, but it's necessary to capture the last group
data[currentKey] = values
I'm specifically not naming a language, since I've had to do this in at least Javascript, C#, Perl, and PHP. If there are language-specific solutions that would be great, but I'm really looking for the most efficient general algorithmic approach.
You can change your code to this:
data = {}
currentKey = ""
foreach (line in inputData) {
key, value = split(line)
if (currentKey != key) {
data[key] = [] // like data.put(key,new ArrayList<String>()) in java
}
data[key].add(value) // like data.get(key).add(value) in java
currentKey = key
}
Here is a solution. First, create a map. For each entry in your data file, find the key and value. Check if the key is in the map. If it isn't, add a new list to the map containing the new value for that key. If the key is already in the map, just add the new value to the list.
def hash = [:]
new File("test.data").eachLine { String line ->
def (key,value) = line.split(/\|/)
hash.get(key, []) << value
}
println hash
It prints out the following map:
[key1:[value1, value2, value3], key2:[value4, value5]]
No need to keep track of currentKey.
Edit: This is written in Groovy, but should be implemented quite similarly in other languages. hash.get() returns the value for the key, or the provided default value (in the above snippet, an empty list), while the left-shift (<<) operator adds something to the list.

does ruby have an elegant way to say array2 = some_lookup_method(array1)

I have an array short_code[] that contains an array of short product identifiers such as ["11111", "2222", "33333"]
I want to create a copy of the array that contains the corresponding 'long code' data:
long_code[i] = my_lookup_long_code(short_code[i])
While simple iteration is easy, I'm wondering, as a relative ruby newbie, what is the 'ruby way' to create an array which is a simply method() applied on every element in the original array?
You can use the map command, which will return a new array with the results of your code block:
long_code = short_code.map{ |code| my_lookup_long_code(code) }

Iterate over Umbraco getAllTagsInGroup result

I'm trying to get a list of tags from a particular tag group in Umbraco (v4.0.2.1) using the following code:
var tags = umbraco.editorControls.tags.library.getAllTagsInGroup("document downloads");
What I want to do is just output a list of those tags. However, if I output the variable 'tags' it just outputs a list of all tags in a string. I want to split each tag onto a new line.
When I check the datatype of the 'tags' variable:
string tagType = tags.GetType().ToString();
...it outputs MS.Internal.Xml.XPath.XPathSelectionIterator.
So question is, how do I get the individual tags out of the 'tags' variable? How do I work with a variable of this data type? I can find examples of how to do it by loading an actual XML file, but I don't have an actual XML file - just the 'tags' variable to work with.
Thanks very much for any help!
EDIT1: I guess what I'm asking is, how do I loop through the nodes returned by an XPathSelectionIterator data type?
EDIT2: I've found this code, which almost does what I need:
XPathDocument document = new XPathDocument("file.xml");
XPathNavigator navigator = document.CreateNavigator();
XPathNodeIterator nodes = navigator.Select("/tags/tag");
nodes.MoveNext();
XPathNavigator nodesNavigator = nodes.Current;
XPathNodeIterator nodesText = nodesNavigator.SelectDescendants(XPathNodeType.Text, false);
while (nodesText.MoveNext())
debugString += nodesText.Current.Value.ToString();
...but it expects the URL of an actual XML file to load into the first line. My XML file is essentially the 'tags' variable, not an actual XML file. So when I replace:
XPathDocument document = new XPathDocument("file.xml");
...with:
XPathDocument document = new XPathDocument(tags);
...it just errors.
Since it is an Iterator, I would suggest you iterate it. ;-)
var tags = umbraco.editorControls.tags.library.getAllTagsInGroup("document downloads");
foreach (XPathNavigator tag in tags) {
// handle current tag
}
I think this does the trick a little better.
The problem is that getAllTagsInGroup returns the container for all tags, you need to get its children.
foreach( var tag in umbraco.editorControls.tags.library.getAllTagsInGroup("category").Current.Select("/tags/tag") )
{
/// Your Code
}

Resources