diff --git a/saddle-core/src/main/scala/org/saddle/index/JoinerImpl.scala b/saddle-core/src/main/scala/org/saddle/index/JoinerImpl.scala index 5a04d454..54335b58 100644 --- a/saddle-core/src/main/scala/org/saddle/index/JoinerImpl.scala +++ b/saddle-core/src/main/scala/org/saddle/index/JoinerImpl.scala @@ -28,8 +28,34 @@ class JoinerImpl[@spec(Boolean, Int, Long, Double) T: ST: ORD] private implicit def wrapArray(arr: Array[Int]): Option[Array[Int]] = Some(arr) - def join(left: Index[T], right: Index[T], how: JoinType): ReIndexer[T] = { - if (left == right) { + def join(left: Index[T], right: Index[T], how: JoinType): ReIndexer[T] = + join(left, right, how, false) + + /** Perform database joins + * + * @param left + * left index to join + * @param right + * right index to join + * @param how + * mode of operation: inner, left outer, right outer, full outer + * @param forceProperSemantics + * if false, then no join is happening if left == right and right is + * returned This is correct for unique indexes, and also practical + * otherwise. If forceProperSemantics true, then the join is done even + * between identical indexes. At the moment forceProperSemantics=true is + * used at no places in saddle's source code (i.e. all frame joins etc use + * the shortcut to not produce proper joins of identical indexes with + * repeated values) + * @return + */ + def join( + left: Index[T], + right: Index[T], + how: JoinType, + forceProperSemantics: Boolean + ): ReIndexer[T] = { + if (left == right && !forceProperSemantics) { ReIndexer(None, None, right) } else if (left.isUnique && right.isUnique) { how match { diff --git a/saddle-core/src/test/scala/org/saddle/IndexSpec.scala b/saddle-core/src/test/scala/org/saddle/IndexSpec.scala index 847e477a..66ce5639 100644 --- a/saddle-core/src/test/scala/org/saddle/IndexSpec.scala +++ b/saddle-core/src/test/scala/org/saddle/IndexSpec.scala @@ -12,9 +12,9 @@ import org.saddle.index.OuterJoin class IndexSpec extends Specification { "Index methods" should { "contiguous works" in { - val ix = Index(1,1,0,0) + val ix = Index(1, 1, 0, 0) ix.isContiguous must_== true - } + } "over flow in join" in { val ix1 = Index(array.randInt(1000000, 0, 3)) val ix2 = Index(array.randInt(10000, 0, 3)) @@ -42,7 +42,18 @@ class IndexSpec extends Specification { } "Index Joins" should { - "Outer join of same non-unique indexes " in { + "Outer join of same non-unique indexes with forceProperSemantics = true makes a join " in { + val ix1 = Index(0, 0) + val ix2 = Index(0, 0) + val res = (new org.saddle.index.JoinerImpl[Int]) + .join(ix1, ix2, index.OuterJoin, forceProperSemantics = true) + + res.index must_== Index(0, 0, 0, 0) + res.lTake.get must_== Array(0, 0, 1, 1) + res.rTake.get must_== Array(0, 1, 0, 1) + + } + "Outer join of same non-unique indexes with forceProperSemantics=false (the default) returns the input " in { val ix1 = Index(0, 0) val ix2 = Index(0, 0) val res = ix1.join(ix2, how = index.OuterJoin)