I want to use JRuby to run some ruby scripts, get a result and continue using Java/Scala. Unfortunately, I don't know how to convert an object from a RubyHash to a Java or Scala Map.
Is there a simple way to do this?
Any suggestions on how to do it?
class org.jruby.RubyHash implements java.util.Map, so, it already is a Java Map, albeit a non-generic "raw" type.
Unfortunately, JRuby's Hash class only inherits the generic to_java method from Kernel, unlike Array which has its own version.
This works:
[1, 2, 3].to_java(:int)
This doesn't, although it looks like it should:
{ 'one' => 1, 'two' => 2 }.to_java(:string, :int)
[It might be worthwhile filing this as a feature request.]
org.jruby.RubyHash implements java.util.Map in a way that it attempts to convert Ruby objects to Java with "normal" Map operations.
e.g. if you have a hash such as: { 'a' => 1, 'b' => 2 } which (internally) means you have RubyString keys mapped to RubyFixnum values in a hash instance, on the Java side hash.get("a") will work fine and return 1 as a java.lang.Long
I would suggest to change your approach slightly: this would involve only changing the way you initialize objects in ruby, the rest should be transparent.
Instead of using pure Ruby hash objects (o=Hash.new or o={}), please use instead java.util.HashMap like in this snippet:
require 'java'
o = java.util.HashMap.new # you could also use o = Java::JavaUtil::HashMap.new
From then on, o would be a java object used as a hash by Ruby code, and can still be accessed using java methods.
Another mode complete snippet:
>> require 'java'
=> true
>> o = Java::JavaUtil::HashMap.new
=> {}
>> o[1] = 2
=> 2
>> o["cm"] = true
=> true
>> p o.keys # ruby methods/interface
[1, "cm"]
=> nil
>> p o.keySet().to_a # java methods
[1, "cm"]
=> nil
Related
I want to get a list of all instants between today and (today - 15) days.
I am understanding I might need to you use LazyList if scala, but I am not so familiar with the syntax since I am new. The java equivalent seems to be
Set <Instant> allPossibleDates =
Stream.iterate(today, date -> date.minus(1, ChronoUnit.DAYS))
.limit(numDates)
.collect(Collectors.toSet());
What is the equivalent for this in Scala?
The LazyList companion object defines an iterate method that lets you define a sequence in terms of a starting point and a step operation (Note: Iterator's companion defines a similar method):
def iterate[A](start: => A)(f: (A) => A): LazyList[A]
In fact it looks essentially the same as the Java version except that the start and f arguments appear in separate parameter lists. Pepper in Scala's syntax sugar for anonymous functions (using _ to represent the function argument), you can do
val today = Instant.now() // or whatever
LazyList
.iterate(today) { _.minus(1, ChronoUnit.DAYS) }
.take(15) // equivalent to `limit` in Java
.to(Set) // equivalent to `collect(...)`
Also note that LazyList defines an overload of iterate which takes a limit, which would replace the .take:
LazyList
.iterate(today, 15) { _.minus(1, ChronoUnit.DAYS) }
.to(Set)
Note that you could do .foreach { instant => /* ... */ } instead of .to(SomeCollectionCompanion) to iterate the contents without allocating the memory for a collection.
In Python 2.x, I could pass custom function to sorted and .sort functions
>>> x=['kar','htar','har','ar']
>>>
>>> sorted(x)
['ar', 'har', 'htar', 'kar']
>>>
>>> sorted(x,cmp=customsort)
['kar', 'htar', 'har', 'ar']
Because, in My language, consonents are comes with this order
"k","kh",....,"ht",..."h",...,"a"
But In Python 3.x, looks like I could not pass cmp keyword
>>> sorted(x,cmp=customsort)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'cmp' is an invalid keyword argument for this function
Is there any alternatives or should I write my own sorted function too?
Note: I simplified by using "k", "kh", etc. Actual characters are Unicodes and even more complicated, sometimes there is vowels comes before and after consonents, I've done custom comparison function, So that part is ok. Only the problem is I could not pass my custom comparison function to sorted or .sort
Use the key keyword and functools.cmp_to_key to transform your comparison function:
sorted(x, key=functools.cmp_to_key(customsort))
Use the key argument (and follow the recipe on how to convert your old cmp function to a key function).
functools has a function cmp_to_key mentioned at docs.python.org/3.6/library/functools.html#functools.cmp_to_key
A complete python3 cmp_to_key lambda example:
from functools import cmp_to_key
nums = [28, 50, 17, 12, 121]
nums.sort(key=cmp_to_key(lambda x, y: 1 if str(x)+str(y) < str(y)+str(x) else -1))
compare to common object sorting:
class NumStr:
def __init__(self, v):
self.v = v
def __lt__(self, other):
return self.v + other.v < other.v + self.v
A = [NumStr("12"), NumStr("121")]
A.sort()
print(A[0].v, A[1].v)
A = [obj.v for obj in A]
print(A)
Instead of a customsort(), you need a function that translates each word into something that Python already knows how to sort. For example, you could translate each word into a list of numbers where each number represents where each letter occurs in your alphabet. Something like this:
my_alphabet = ['a', 'b', 'c']
def custom_key(word):
numbers = []
for letter in word:
numbers.append(my_alphabet.index(letter))
return numbers
x=['cbaba', 'ababa', 'bbaa']
x.sort(key=custom_key)
Since your language includes multi-character letters, your custom_key function will obviously need to be more complicated. That should give you the general idea though.
I don't know if this will help, but you may check out the locale module. It looks like you can set the locale to your language and use locale.strcoll to compare strings using your language's sorting rules.
Use the key argument instead. It takes a function that takes the value being processed and returns a single value giving the key to use to sort by.
sorted(x, key=somekeyfunc)
While working through converting some Java code over to Scala, I discovered while there is a contains method for Scala's Set, there isn't a containsAll method. Am I just missing the correct method name?
Here's a bit of code I worked up to fill in the gap so I could quickly get back to working. Is it sufficient, or am I missing some subtlety?
def containsAll[A](set: Set[A], subset: Set[A]): Boolean =
if (set.size >= subset.size)
subset.forall(a => set.contains(a))
else
false
There is subsetOf, which tests whether or not the elements of a Set are contained within another Set. (Kind of the reverse in terms of the expression)
val set = Set(1,2,3,4)
val subset = Set(1,2)
scala> subset.subsetOf(set)
res0: Boolean = true
scala> set.subsetOf(subset)
res1: Boolean = false
In Scala, Set is equipped with set operations such as intersect, thus for instance
set.intersect(subset) == subset
conveys the semantics of containsAll, even that subsetOf as already mentioned proves the most succinct.
It's worth adding that you can make derived helper methods like containsAll available on Set[T] if you want, by using an implicit enriched class. You might also consider making a variadic overload:
implicit class RichSet[T](val x: Set[T]) extends AnyVal {
def containsAll(y: Set[T]): Boolean = y.subsetOf(x)
def containsAll(y: T*): Boolean = x.containsAll(y.toSet)
}
So then you can do:
Set(1, 2, 3).containsAll(Set(1, 2))
Or:
Set(1, 2, 3).containsAll(1, 2)
Previous answers are all good, I'm just throwing-in another option. This one would also work with Lists which don't have subsetOf method:
Set(1,2,3) forall(Set(3, 2, 1) contains)
I'm currently working on accessing HBase using python3. The way I'm doing is using py4j to call JAVA APIs that I'm writing to access HBase.
I've a question related to creating a Put object which takes a qualifier and value.
I want to pass a dictionary to a JAVA class which expects a hashmap. Is it possible through py4j.
I don't want to call Put for every column qualifier iteratively. I want to pass the dict to py4j and it should be received as HashMap on JAVA side.
Could you please some hints/pointers to how can this be done...
There are two ways to do what you want:
You can create a java.util.HashMap() and use it as a dict on the python side. This is good if you pass the dictionary a lot, but you do not modify it often on the python side. This is also good if the dictionary is modified on the java side and you want to see the modifications on the python side.
Py4J can automatically convert a python dict to a HashMap when calling a Java method. Note that the dictionary will be copied and that any change performed on the Java side won't be reflected on the Python side.
The easiest solution would be #1 I believe:
>>> m = gateway.jvm.java.util.HashMap()
>>> m["a"] = 0
>>> m.put("b",1)
>>> m
{u'a': 0, u'b': 1}
>>> u"b" in m
True
>>> del(m["a"])
>>> m
{u'b': 1}
>>> m["c"] = 2
I am creating a Clojure interface to a Java API with a method that returns a java.util.LinkedHashSet.
Firstly, is the idiomatic Clojure way of handling this to convert the LinkedHashSet to a clojure data structure?
Secondly, what is the best method for converting Java collections into Clojure data structures?
There are lots of options, since Clojure plays very nicely with Java collections. It depends on exactly what data structure you want to use in Clojure.
Here's some examples:
;; create a HashSet
(def a (java.util.HashSet.))
(dotimes [i 10] (.add a i))
;; Get all the values as a sequence
(seq a)
=> (0 1 2 3 4 5 6 7 8 9)
;; build a new HashSet containing the values from a
(into #{} a)
#{0 1 2 3 4 5 6 7 8 9}
;; Just use the HashSet directly (high performance, no copy required)
(.contains a 1)
=> true
(.contains a 100)
=> false
Regarding when to use each of these, I'd suggest the following advice:
If you are trying to wrap a Java library and present a clean Clojure API, then I'd suggest converting to the equivalent Clojure data structures. This is what Clojure users will expect, and you can hide the potentially messy Java interop details. As a bonus, this will make things immutable so that you don't run the risk of Java collections mutating while you use them.
If you just want to use the Java API quickly and efficiently, just use Java interop directly on the Java collections.
The idiomatic way to convert java collections to clojure is to use the (seq) function, which is already called by most functions operating on sequences.
(def s (java.util.LinkedHashSet.))
#'user/s
user> (seq s)
nil
user> (.add s "foo")
true
user> (seq s)
("foo")
user>
I honestly don't know if there's a universally accepted practice, but here's Chris Houser arguing against Java to Clojure adapters as you break compatibility with the original Java API.
To perform the translation you asked for, simply use into:
user=> (import java.util.LinkedHashSet)
java.util.LinkedHashSet
user=> (def x (LinkedHashSet.))
#'user/x
user=> (.add x "test")
true
user=> (def y (into #{} x))
#'user/y
user=> y
#{"test"}