XOMW: Add PHP array-diff and array-diff-key [#632]

staging
gnosygnu 4 years ago
parent ebe82bea6a
commit 04c499ce3e

@ -30,10 +30,14 @@ import gplx.core.brys.Bry_bfr_able;
import gplx.core.strings.String_bldr;
import gplx.core.strings.String_bldr_;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
// REF.PHP: https://www.php.net/manual/en/language.types.array.php
// also has static functions; REF.PHP: https://www.php.net/manual/en/ref.array.php
// REF.PHP:https://www.php.net/manual/en/language.types.array.php
// also has static functions; REF.PHP:https://www.php.net/manual/en/ref.array.php
public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
private final Ordered_hash hash = Ordered_hash_.New();
private int newMemberIdx;
@ -138,6 +142,9 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
XophpArrayItm itm = (XophpArrayItm)hash.Get_by(key);
return itm == null ? null : (T)itm.Val();
}
public XophpArrayItm Get_by_itm(String key) {
return (XophpArrayItm)hash.Get_by(key);
}
public void Set(int key, Object val) {
this.Set(XophpArrayItm.NewInt(key, val));
}
@ -160,6 +167,9 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
hash.Del(itm.Key());
}
}
public void Del_by(String key) {
hash.Del(key);
}
public XophpArrayItm[] To_ary() {
return (XophpArrayItm[])hash.To_ary(XophpArrayItm.class);
}
@ -309,7 +319,7 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
return len == 0 ? null : ((XophpArrayItm)array.hash.Get_at(len - 1)).Val();
}
// REF.PHP: https://www.php.net/manual/en/function.array-values.php
// REF.PHP:https://www.php.net/manual/en/function.array-values.php
public static XophpArray array_values(XophpArray array) {
XophpArray rv = new XophpArray();
int len = array.Len();
@ -482,7 +492,7 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
return sb.To_str_and_clear();
}
// REF.PHP: https://www.php.net/manual/en/function.in-array.php
// REF.PHP:https://www.php.net/manual/en/function.in-array.php
public static boolean in_array(Object needle, XophpArray haystack) {return in_array(needle, haystack, false);}
public static boolean in_array(Object needle, XophpArray haystack, boolean strict) {
// if strict, cache needleType
@ -519,7 +529,7 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
return false;
}
// REF.PHP: https://www.php.net/manual/en/function.array-shift.php
// REF.PHP:https://www.php.net/manual/en/function.array-shift.php
// Returns the shifted value, or NULL if array is empty or is not an array.
public static Object array_shift(XophpArray array) {
if (array == null) {
@ -544,7 +554,7 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
return itms[0].Val();
}
// REF.PHP: https://www.php.net/manual/en/function.array-filter.php
// REF.PHP:https://www.php.net/manual/en/function.array-filter.php
public static final int ARRAY_FILTER_USE_BOTH = 1, ARRAY_FILTER_USE_KEY = 2, ARRAY_FILTER_USE_VAL = 0; // XO:USE_VAL is not PHP
public static XophpArray array_filter(XophpArray array) {return array_filter(array, NULL_CALLBACK, 0);}
public static XophpArray array_filter(XophpArray array, XophpCallback callback) {return array_filter(array, callback, 0);}
@ -578,4 +588,70 @@ public class XophpArray<T> implements Bry_bfr_able, Iterable<T> {
return !XophpObject_.empty_obj(arg);
}
}
// REF.PHP:https://www.php.net/manual/en/function.array-diff.php
public static XophpArray array_diff(XophpArray array1, XophpArray array2, XophpArray... arrays) {
// remove elements
Map<String, List<String>> valMap = array_diff__build_val_map(array1);
int array1_len = array1.Len();
array_diff__remove_common_vals(valMap, array1, array2);
for (XophpArray array : arrays) {
// update map, if array contents changed
if (array1_len != array1.Len()) {
valMap = array_diff__build_val_map(array1);
array1_len = array1.Len();
}
array_diff__remove_common_vals(valMap, array1, array);
}
return array1;
}
private static Map<String, List<String>> array_diff__build_val_map(XophpArray array) {
Map<String, List<String>> map = new HashMap<>();
int len = array.Len();
for (int i = 0; i < len; i++) {
XophpArrayItm itm = array.Get_at_itm(i);
// get val as String
String valStr = XophpObject_.ToStr(itm.Val());
List<String> keyList = map.get(valStr);
if (keyList == null) {
keyList = new ArrayList<>();
map.put(valStr, keyList);
}
keyList.add(itm.Key());
}
return map;
}
private static void array_diff__remove_common_vals(Map<String, List<String>> lhsValMap, XophpArray lhs, XophpArray rhs) {
int rhsLen = rhs.Len();
for (int i = 0; i < rhsLen; i++) {
XophpArrayItm rhsItm = rhs.Get_at_itm(i);
String rhsVal = XophpObject_.ToStr(rhsItm.Val());
List<String> lhsKeyList = lhsValMap.get(rhsVal);
if (lhsKeyList != null) {
for (String lhsKey : lhsKeyList) {
lhs.Del_by(lhsKey);
}
}
}
}
// REF.PHP:https://www.php.net/manual/en/function.array-diff-key
public static XophpArray array_diff_key(XophpArray array1, XophpArray array2, XophpArray... arrays) {
// remove elements
array_diff_key__remove_common_key(array1, array2);
for (XophpArray array : arrays) {
array_diff_key__remove_common_key(array1, array);
}
return array1;
}
private static void array_diff_key__remove_common_key(XophpArray lhs, XophpArray rhs) {
int rhsLen = rhs.Len();
for (int i = 0; i < rhsLen; i++) {
XophpArrayItm rhsItm = rhs.Get_at_itm(i);
String rhsKey = rhsItm.Key();
if (lhs.Has(rhsKey)) {
lhs.Del_by(rhsKey);
}
}
}
}

@ -23,8 +23,8 @@ import gplx.String_;
import gplx.Type_;
import gplx.core.brys.Bry_bfr_able;
public class XophpArrayItm implements Bry_bfr_able {
XophpArrayItm(boolean keyIsInt, int keyAsInt, String key, Object val) {
public class XophpArrayItm<T> implements Bry_bfr_able {
XophpArrayItm(boolean keyIsInt, int keyAsInt, String key, T val) {
this.keyIsInt = keyIsInt;
this.keyAsInt = keyAsInt;
this.key = key;
@ -33,7 +33,7 @@ public class XophpArrayItm implements Bry_bfr_able {
public boolean KeyIsInt() {return keyIsInt;} private final boolean keyIsInt;
public int KeyAsInt() {return keyAsInt;} private final int keyAsInt;
public String Key() {return key;} private final String key;
public Object Val() {return val;} public void Val_(Object v) {this.val = v;} private Object val;
public T Val() {return val;} public void Val_(T v) {this.val = v;} private T val;
public void To_bfr(Bry_bfr bfr) {
bfr.Add_str_u8(key).Add_byte_eq();

@ -96,4 +96,9 @@ public class XophpObject_ {
// equivalent to ??
public static Object Coalesce(Object o, Object or) {return isset_obj(o) ? o : or;}
// equivalent to (string)o; see https://www.php.net/manual/en/function.array-diff.php
public static String ToStr(Object o) {
return o.toString();
}
}

@ -15,15 +15,12 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.mediawiki.includes.libs.services;
import gplx.xowa.mediawiki.XophpArray;
import gplx.xowa.mediawiki.XophpArray;
import gplx.xowa.mediawiki.XophpCallback;
import gplx.xowa.mediawiki.XophpObject_;
import gplx.xowa.mediawiki.XophpType_;
/*
XOTODO:
* array_diff: https://www.php.net/manual/en/function.array-diff.php
* array_diff_key: https://www.php.net/manual/en/function.array-diff-key
* XomwAssert: /vendor/wikimedia/Assert/src
*/
// MW.SRC:1.33.1

@ -389,6 +389,60 @@ public class XophpArrayStaticTest {
XophpArray.reset(array);
Gftest.Eq__str("step one", (String)XophpArray.current(array));
}
@Test public void array_diff() {
// test To_str
XophpArray<String> array1 = new XophpArray().Add("a", "0");
XophpArray<Integer> arrayInt = new XophpArray().Add("a", 0);
fxt.Test__eq
( new XophpArray<String>()
, XophpArray.array_diff(array1, arrayInt)
);
// test many
XophpArray<String> array2, array3, array4;
array1 = new XophpArray().Add_many("a", "b", "c", "d");
array2 = new XophpArray().Add_many("a");
array3 = new XophpArray().Add_many("c");
array4 = new XophpArray().Add_many("d");
fxt.Test__eq
( new XophpArray<String>().Add(1, "b")
, XophpArray.array_diff(array1, array2, array3, array4)
);
// PHP examples
// Example #1 array_diff() example
array1 = new XophpArray().Add("a", "green").Add_many("red", "blue", "red");
array2 = new XophpArray().Add("b", "green").Add_many("yellow", "red");
fxt.Test__eq
( new XophpArray<String>().Add(1, "blue")
, XophpArray.array_diff(array1, array2)
);
}
@Test public void array_diff_key() {
// PHP examples
// Example #1 array_diff_key() example
XophpArray<Integer> array1, array2;
array1 = new XophpArray<>().Add("blue", 1).Add("red", 2).Add("green", 3).Add("purple", 4);
array2 = new XophpArray<>().Add("green", 5).Add("yellow", 7).Add("cyan", 8);
fxt.Test__eq
( new XophpArray<String>().Add("blue", 1).Add("red", 2).Add("purple", 4)
, XophpArray.array_diff_key(array1, array2)
);
XophpArray<Integer> array3;
array1 = new XophpArray<>().Add("blue", 1).Add("red", 2).Add("green", 3).Add("purple", 4);
array2 = new XophpArray<>().Add("green", 5).Add("yellow", 7).Add("cyan", 8);
array3 = new XophpArray<>().Add("blue", 6).Add("yellow", 7).Add("mauve", 8);
fxt.Test__eq
( new XophpArray<String>().Add("red", 2).Add("purple", 4)
, XophpArray.array_diff_key(array1, array2, array3)
);
}
}
class XophpArray_fxt {
public XophpArray Make() {return new XophpArray();}

Loading…
Cancel
Save