Kotlin - Find matching objects in array - arrays

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.

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]

How prevent Object.keys() sort?

The problem with the ECMA standard for sort of Object.keys() is known:
Object.keys() handle all keys with integer (example: 168), including integer as strings (example: "168"), as a integer. The result is, both are the same (168 === "168"), and overwrite itself.
var object = {};
object["168"] = 'x';
object[168] = 'y';
Object.keys(object); // Array [ "168" ]
object[Object.keys(object)]; // "y"
Interestingly, all keys (including pure integer keys) are returned as a string.
The ecma262 wrote about this: All keys will be handle as a integer, expect the key is a String but is not an array index.
https://tc39.es/ecma262/#sec-ordinaryownpropertykeys
That should tell us: 168 === "168". A toString() do not solve the problem.
var object = {};
object[[3].toString()] = 'z';
object[[1].toString()] = 'x';
object[[2].toString()] = 'y';
Object.keys(object);
// Array(3) [ "1", "2", "3" ]
Paradoxically, in this case, only integer apply as "enumerable" (it's ignoring array.sort(), that sort also strings with letters.).
My question about this is simple: How can i prevent the sort function in Object.keys()? I have testet the Object.defineProperties(object, 1, {value: "a", enumerable: true/false}), but that mean not realy enumerable in the case of integer or string or integer-like string. It means only should it be counted with or not. It means "counted" like omit (if it false), not "enumerabled" like ascending or descending.
A answere like that is not a good answer: Please use only letters [a-zA-Z] or leastwise a letter at the first position of keyword.
What I want: That the keys are not sorted, but output in the order in which they were entered, whether integer, string or symbol.
Disclaimer: Please solutions only in JavaScript.
Javascript Objects are unordered by their nature. If you need an ordered object-like variable I would suggest using a map.
To achieve what you're looking for with a map instead of object you'd do something like the below:
var map1 = new Map();
map1.set("123", "c");
map1.set(123, "b");
var iterator1 = map1.keys();
var myarray = [];
for (var i = 0; i < map1.size; i++) {
myarray.push(iterator1.next().value);
}
console.log(myarray);
// Array ["123", 123]
Unfortunately it's not compatible with IE and I'm not sure how else you could achieve what you need without it. A quick Google did return something about jQuery maps, though.
If you don't want to use jQuery and still need to support IE some points are below:
Is there anything stopping you using an array rather than JS object to store the data you need? This will retain the order per your requirements unlike objects. You could have an object entry in each iteration which represents the key then use a traditional foreach to obtain them as an array. I.e.
The array:
var test_array = [
{key: 123, value: 'a value here'},
{key: "123", value: 'another value here'}
];
// console.log(test_array);
Getting the keys:
var test_array_keys = [];
test_array.forEach(function(obj) { test_array_keys.push(obj['key']); } );
// console.log(test_array_keys);
Then if you needed to check whether the key exists before adding a new entry (to prevent duplicates) you could do:
function key_exists(key, array)
{
return array.indexOf(key) !== -1;
}
if(key_exists('12345', test_array_keys))
{
// won't get here, this is just for example
console.log('Key 12345 exists in array');
}
else if(key_exists('123', test_array_keys))
{
console.log('Key 123 exists in array');
}
Would that work? If not then the only other suggestion would be keeping a separate array alongside the object which tracks the keys and is updated when an entry is added or removed to/from the object.
Object Keys sorted and store in array
First Creating student Object. then sort by key in object,last keys to store in array
const student={tamil:100, english:55, sci:85,soc:57}
const sortobj =Object.fromEntries(Object.entries(student).sort())
console.log(Object.keys(sortobj))
use map instead of an object.
let map = new Map()
map.set("a", 5)
map.set("d", 6)
map.set("b", 12)
to sort the keys (for example, to update a chart data)
let newMap = new Map([...map.entries()].sort())
let keys = Array.from(newMap.keys()) // ['a','b','d']
let values = Array.from(newMap.values()) // [5,12,6]

Best way to find needed element in array of objects

I have array of objects of my class. My class have variable for name that is unique for every object created. Now, I want to find, say, object in array that has a name "test". I wanted to try something like creating second array with just names as elements and when I create new object in my first array to create object in second array so that they share index number. Something like this:
arrayOfObjects.push(new obj("test"));
arrayOfNames.push("test");
function findIndexNumberOf(name){
for(var i = 0; i < arrayOfNames.length; i++){
if(arrayOfNames[i] === name)
return i;
}
}
But I think that this is pretty robust solution so I'm wondering is there better/smarter/faster way of doing this.
If you want to find the index of an item, it's generally the easiest to use indexOf:
const haystack = ["this", "is", "a", "test"];
const needle = "this";
const result = haystack.indexOf(needle);
However, this will work with primitive types. Assuming you have an array of objects, comparing them will require a different approach. Here are some one-liners:
const haystack = [new String("this"), new String("is"), new String("a"), new String("test")];
const needle = "test";
const result1 = haystack.indexOf(haystack.filter(item => item == needle)[0]);
const result2 = haystack.indexOf(haystack.filter(item => item.toString() === needle.toString())[0]);
const result3 = haystack.map(item => item.toString()).indexOf(needle.toString());
const result4 = haystack.indexOf(haystack.find(item => item.toString() === needle.toString()));
result1 filters the haystack using the == operator, thus ignoring the fact that the compared values are actually different types. The first element of the filtered array is then fed to indexOf. This will allow you to use a primitive string as the needle and search through a haystack of objects.
result2 uses the same approach, but casts both compared values to a primitive string, making sure they're both of the same type. This will allow you to mix and match primitives and String objects liberally, both in the haystack and needle.
result3 maps all haystack values to primitive strings and then uses indexOf on that new array of primitives. I also added toString to the needle to ensure it's also a primitive. This works similar to your approach, but the mapping is run every time you search for a needle. This is probably suboptimal.
result4 uses Array.prototype.find to locate the target object on the haystack and then feeds the result to indexOf. This might be the fastest, but I have no empirical data to back this up.
Now, in case you wanted to find the actual item, not just its index, you're best off using Array.prototype.find:
const result = haystack.find(item => item == needle);
or, in case both are String objects:
const result = haystack.find(item => item.toString() === needle.toString());
You can use the find method of Arrays object:
const myObject = arr.find(o => o.name === 'the_name_you_search');

Scala Converting Each Array Element to String and Splitting

I have an array loaded in, and been playing around in the REPL but can't seem to get this to work.
My array looks like this:
record_id|string|FALSE|1|
offer_id|decimal|FALSE|1|1,1
decision_id|decimal|FALSE|1|1,1
offer_type_cd|integer|FALSE|1|1,1
promo_id|decimal|FALSE|1|1,1
pymt_method_type_cd|decimal|FALSE|1|1,1
cs_result_id|decimal|FALSE|1|1,1
cs_result_usage_type_cd|decimal|FALSE|1|1,1
rate_index_type_cd|decimal|FALSE|1|1,1
sub_product_id|decimal|FALSE|1|1,1
campaign_id|decimal|FALSE|1|1,1
When I run my command:
for(i <- 0 until schema.length){
val convert = schema(i).toString;
convert.split('|').drop(2);
println(convert);
}
It won't drop anything. It also is not splitting it on the |
Strings are immutable, and so split and drop don't mutate the string - they return a new one.
You need to capture the result in a new val
val split = convert.split('|').drop(2);
println(split.mkString(" "));
Consider also defining a lambda function for mapping each item in the array, where intermediate results are passed on with the function,
val res = schema.map(s => s.toString.split('|').drop(2))

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