Remove a group on strings from an object in ruby - arrays

So, I have the following
removed_caps = self.user.caps.reject { |c| c == 'test' || c == 'test1'}
I want to have test and test1 as configs so that I can add to these in the future.
so something like:
caps_to_remove = ENV['BLACK_LIST']
split_caps_to_remove = caps_to_remove.split(' ')
puts split_caps_to_remove -->>> ["test", "test1"]
How do I incorporate split_caps_to_remove in the original code?
Thanks.

You could change your code to:
removed_caps = self.user.caps.reject { |c| split_caps_to_remove.include?(c) }

Use Fixed-String Methods
Assuming you have some variables defined as in the example below, then you can use String#delete or String#delete! as a faster way to remove your unwanted characters. Consider:
caps = ENV['BLACKLIST']='TE'
str1, str2 = 'TEST', 'TEST1'
[str1, str2].map { _1.delete caps }
#=> ["S", "S1"]
Fewer methods in a chain are often faster, and String methods that operate on a fixed String are often and order of magnitude faster Regexp-related methods like #gsub or iterating over a collection.
See Also
You didn't provide your actual input or calling code, but in newer Ruby versions (including 3.1.2) there are some other related methods (some with bang methods, which are both useful and faster if you aren't using frozen strings) that may also help:
String#delete_prefix
String#delete_suffix
String#downcase
String#swapcase

Related

How to get a specific index value in array by using map and stream in Kotlin?

I want to get a list of String in ArrayList<Array<String>> by using stream() and map in Kotlin.
Each Array<String> of my arrayList has 3 values and I want to get the first index value and the last index value of each array.
This is my code:
fun main(args: Array<String>) {
val result: List<String>
val obj1 = arrayOf("fruit", "Mangue", "Africa")
val obj2 = arrayOf("Milk", "Soja", "Europ")
val obj3 = arrayOf("Meat", "cochon","Asia")
val myArrayList: ArrayList<Array<String>> = ArrayList<Array<String>>(3)
val myList: MutableList<Array<String>> = mutableListOf<Array<String>>()
myList.add(obj1)
myList.add(obj2)
myList.add(obj3)
myArrayList.addAll(myList)
result = myArrayList.stream().map{it -> ("${it[0]}-${it[2]}")}.toList()
println("ArrayList of objects :")
println(myArrayList)
println("my list of String result")
println(result)
}
I want to have this list of String in my result:
[fruit-africa,milk-Europ,Meat-Asia]
Also, when I print myArrayList, I have a bad result:
ArrayList of objects :
[[Ljava.lang.String;#5caf905d, [Ljava.lang.String;#27716f4, [Ljava.lang.String;#8efb846]
How can I do it, please?
Your Question
When I run your code, this is the output I see:
ArrayList of objects :
[[Ljava.lang.String;#5b480cf9, [Ljava.lang.String;#6f496d9f, [Ljava.lang.String;#723279cf]
my list of String result
[fruit-Africa, Milk-Europ, Meat-Asia]
And in your question, you have:
I want to have this list of String in my result:
[fruit-africa,milk-Europ,Meat-Asia]
So, it looks like you already have the output you want for result. The only difference from the actual output is the lack of a space after each comma. If you don't want that space, then use joinToString to customize the output:
println(result.joinToString(",", "[", "]"))
As for:
[[Ljava.lang.String;#5b480cf9, [Ljava.lang.String;#6f496d9f, [Ljava.lang.String;#723279cf]
You see that output because arrays don't override the toString() function, and therefore use the default implementation. In Kotlin, you can use contentToString() to get similar output as you see when printing a List.
println(myArrayList.joinToString(", ", "[", "]") { it.contentToString() })
So, here is the updated code with the above changes:
fun main(args: Array<String>) {
val result: List<String>
val obj1 = arrayOf("fruit", "Mangue", "Africa")
val obj2 = arrayOf("Milk", "Soja", "Europ")
val obj3 = arrayOf("Meat", "cochon","Asia")
val myArrayList: ArrayList<Array<String>> = ArrayList<Array<String>>(3)
val myList: MutableList<Array<String>> = mutableListOf<Array<String>>()
myList.add(obj1)
myList.add(obj2)
myList.add(obj3)
myArrayList.addAll(myList)
result = myArrayList.stream().map{it -> ("${it[0]}-${it[2]}")}.toList()
println("ArrayList of objects :")
println(myArrayList.joinToString(", ", "[", "]") { it.contentToString() })
println("my list of String result")
println(result.joinToString(",", "[", "]"))
}
Which gives this output:
ArrayList of objects :
[[fruit, Mangue, Africa], [Milk, Soja, Europ], [Meat, cochon, Asia]]
my list of String result
[fruit-Africa,Milk-Europ,Meat-Asia]
Potential Improvements
With all that said, there are a few things you can simplify in your code:
This is a minor point, but since you don't use the args parameter you can actually omit it.
Your myList is not necessary; you can add your arrays directly to myArrayList.
Given the small number of elements in each array, and the small number of arrays, you can actually create the List<Array<String>> and populate it with a single listOf.
For variable types, you should prefer using List, the interface, rather than ArrayList, the implementation. This is known as "programming to an interface". Preferring List also means better use of listOf and mutableListOf, which are the idiomatic ways of creating lists in Kotlin.
You should prefer using List over arrays. In other words, create a List<List<String>> instead of a List<Array<String>>.
Lists do override the toString() method, providing readable output. Also, lists have better API support and work better with generics.
You don't need to use stream(). Kotlin provides many extension functions for arrays and Iterables, one of those being map which returns a List. Yes, these transformation functions are eagerly evaluated, unlike with streams, but given you're only performing one transfomration this doesn't really matter (in fact, the stream is likely less performant).
See kotlin.collections for the available built-in extension functions.
Given you want the first and last elements of each array, I would use first() and last().
Here is the simplified code (I added explicit types to make it clearer what the variables reference):
fun main() {
val lists: List<List<String>> = listOf(
listOf("Fruit", "Mangue", "Africa"),
listOf("Milk", "Soja", "Europe"),
listOf("Meat", "Cochon", "Asia")
)
println("List of lists of strings:")
println(lists)
val result: List<String> = lists.map { "${it.first()}-${it.last()}" }
println("Result:")
println(result)
}
Output:
List of Arrays:
[[Fruit, Mangue, Africa], [Milk, Soja, Europe], [Meat, Cochon, Asia]]
Result:
[Fruit-Africa, Milk-Europe, Meat-Asia]

Kotlin - Find matching objects in array

Let's say I have an array of strings and I want to get a list with objects that match, such as:
var locales=Locale.getAvailableLocales()
val filtered = locales.filter { l-> l.language=="en" }
except, instead of a single value I want to compare it with another list, like:
val lang = listOf("en", "fr", "es")
How do I do that? I'm looking for a one-liner solution without any loops. Thanks!
Like this
var locales = Locale.getAvailableLocales()
val filtered = locales.filter { l -> lang.contains(l.language)}
As pointed out in comments, you can skip naming the parameter to the lambda, and use it keyword to have either of the following:
val filtered1 = locales.filter{ lang.contains(it.language) }
val filtered2 = locales.filter{ it.language in lang }
Just remember to have a suitable data structure for the languages, so that the contains() method has low time complexity like a Set.

In Perl, how do I detect whether a (tied) array is empty without looking at its size?

I have been tinkering with the idea of hiding some implementation
details of an IPC mechanism behind a tied array. The goal is to be
able to do something like this on the server side:
# setup code here. Client provides a function name, we find
# a function to deal with the request:
my $coderef = lookup($method);
local #_;
tie #_, 'My::IPC';
#ret = &$coderef;
The My::IPC class will then read serialized objects from a
pipe/socket as needed (triggered through the SHIFT or FETCH
method).
I would like to provide the authors of the server functions with ways
to write his IPC-accessible functions in a way that he would write
local functions, i.e.:
sub f1 {
while (my $param = shift) {
...
}
}
... as well as ...
sub f2 {
my ($foo, $bar, $baz, %flags) = #_;
...
}
f1 is intended to be able to deal with streams of data that may be
larger than the amount of RAM available -- as long as each individual
object fits into RAM after deserialization, everything is fine. f2
is intended for "simpler" functions where the argument list can be
slurped into RAM.
To support both scenarios, the TIEARRAY constuctor and the SHIFT,
FETCH, and FETCHSIZE methods need to be implemented. I consider
that part solved. What bothers me is that I can't seem to find a way
that lets me transmit undef values to f1 because even in list
context, shift returns undef when used on an empty array.
Something like
#params = splice #_, 0, 1;
might work here, but that does not exactly look like the obvious
solution to users.
I could solve this by making a slight modification to f1 and by
implementing FETCHSIZE in a way that it returns 1 as long as there
is data available:
sub f3 {
while (#_) {
my $param = shift;
...
}
}
But this would break f2 because only the first element would get
assigned. Apparently, FETCHSIZE needs to provide an accurate value,
but to get that accurate value, the entire array needs to be slurped
into RAM -- which defeats the purpose of iterating over it.
Is there an elegant way to support both a "streaming" model (f1,
f3) and a more simple function-call-like model (f2) with the same
tied array implementation?
Arrays have a length. If your code can't behave like an array, giving it the interface of an array isn't a good idea.
You can get the underlying object using tied
sub f1 {
while ( my ($param) = tied(#_)->next() ) {
...
}
}
sub f2 {
my ($foo, $bar, $baz, %flags) = #_;
...
}
But avoiding tying something that isn't array-like is probably best.
sub f1 {
my $o = shift;
while ( my ($param) = $o->next ) {
...
}
}
sub f2 {
my ($foo, $bar, $baz, %flags) = shift->all;
...
}
Note that next is called in list context, so it has the option of returning an empty list in addition to returning undef, allowing the end of the iteration to be distinguishable from undef.

ColdFusion 8 ArrayFind Substitute

I have an array that has a structure of ImageID and Custnum.
I need to find a particular ImageID and retrieve the Custnum for it.
I’m using ColdFusion 8 which does not have an ArrayFind command.
How would I do this without looping through each item? Thanks.
Your question may be answered to a point here "Is there a function similar to ArrayFind from ColdFusion 9 in ColdFusion 8?" but I don't see any other way apart from looping.
You can always create and use an UDF but it would have to use looping.
Why exactly you don't want to use looping anyway? Do you have that many elements in the array? Just remember to use cfbreak after finding your element to stop going through the rest of the array.
Given your situation, I don't think arrayFind() would help you much anyhow, as to find something with arrayFind(), you need to know exactly what you're looking for anyhow. And whilst you know your ImageID, you don't know the Custnum associated with it (hence your underlying problem).
There's nothing native in CF which can help you here, but there's a UDF on CFLib - structFindKeyWithValue() which'll do the trick.
It's written for CF9, but is easily backported to CF8. The modified, CF8-friendly version - is in the example below:
<cfscript>
a = [
{ImageID=1, Custnum=1},
{ImageID=2, Custnum=2},
{ImageID=3, Custnum=3},
{ImageID=4, Custnum=4}
];
testStruct = {a=a};
result = structFindKeyWithValue(testStruct, "ImageID", 2, "ONE");
function structFindKeyWithValue(struct, key, value, scope){
var keyResult = false;
var valueResult = [];
var i = 0;
if (!isValid("regex", arguments.scope, "(?i)one|all")){
throw(type="InvalidArgumentException", message="Search scope #arguments.scope# must be ""one"" or ""all"".");
}
keyResult = structFindKey(struct, key, "all");
for (i=1; i <= arrayLen(keyResult); i++){
if (keyResult[i].value == value){
arrayAppend(valueResult, keyResult[i]);
if (scope == "one"){
break;
}
}
}
return valueResult;
}
</cfscript>
<cfdump var="#result#">
Note that because it's a stuct function, you need to wrap your data in a struct first. Other than that it's fairly straight fwd.

Is there a way to convert a struct into an array without using a loop?

I'm curious, is there another way to convert a struct into an array in Coldfusion without looping over it? I know it can be done this way if we use a for in loop:
local.array = [];
for (local.value in local.struct)
{
arrayAppend(local.array, local.value);
}
Does StructKeyArray suit your requirements?
Description
Finds the keys in a ColdFusion
structure.
If you are trying to maintain order in your structure you could always use a Java LinkedHashMap like so:
cfmlLinkedMap = createObject("Java", "java.util.LinkedHashMap").init();
cfmlLinkedMap["a"] = "Apple";
cfmlLinkedMap["b"] = "Banana";
cfmlLinkedMap["c"] = "Carrot";
for(key in cfmlLinkedMap){
writedump(cfmlLinkedMap[key]);
}
You could also do the same thing in a more "java" way not sure why you'd want to but its always an option:
//no need to init
linkedMap = createObject("Java", "java.util.LinkedHashMap");
//java way
linkedMap.put("d","Dragonfruit");
linkedMap.put("e","Eggplant");
linkedMap.put("f","Fig");
//loop through values
iterator = linkedMap.entrySet().iterator();
while(iterator.hasNext()){
writedump(iterator.next().value);
}
//or
//loop through keys
iterator = linkedMap.keySet().iterator();
while(iterator.hasNext()){
writedump(linkedMap.get(iterator.next()));
}
Just remember that the keys are case SeNsItIvE!
In Coldfusion 10 or Railo 4, if you want an array of values (instead of keys), you can use the Underscore.cfc library like so:
_ = new Underscore();// instantiate the library
valueArray = _.toArray({first: 'one', second: 'two'});// returns: ['one','two']
Note: Coldfusion structures are unordered, so you are not guaranteed to have any specific order for the values in the resulting array.
(Disclaimer: I wrote Underscore.cfc)

Resources