I have tried several options, not sure what I am missing? thanks much. the filter_value in output always seems to be null. I am expecting to see something like this:
FILTER array count : 2
lov_for : Ids
v_count_2 : 3
filter_value : 1
filter_value : 2
filter_value : 3
lov_for : Amounts
v_count_2 : 4
filter_value : 20
filter_value : 30
filter_value : 50
filter_value : 60
DECLARE
v_a VARCHAR2(5000) :=
'{
"lovFilters": [
{
"lovFor": "Ids",
"values": [1,2,3]
},
{
"lovFor": "Amounts",
"values": [20,30,50,60]
}
]
}';
v_array_count NUMBER := 0;
lov_for VARCHAR2(30);
filter_value VARCHAR2(256);
v_count_2 NUMBER:= 0;
BEGIN
APEX_JSON.parse(v_a);
v_array_count := APEX_JSON.get_count(p_path => 'lovFilters');
dbms_output.put_line ('FILTER array count : '||v_array_count);
FOR lr_i IN 1 .. v_array_count
LOOP
dbms_output.put_line ('-------------------------');
lov_for := APEX_JSON.get_varchar2 (p_path => 'lovFilters[%d].lovFor', p0 => lr_i);
dbms_output.put_line ('lov_for : '||lov_for);
v_count_2 := APEX_JSON.get_count(p_path => 'lovFilters[%d].values', p0 => lr_i);
dbms_output.put_line ('v_count_2 : '||v_count_2);
dbms_output.put_line ('--------------------------');
FOR lr_n IN 1 .. v_count_2
LOOP
filter_value :=
APEX_JSON.get_varchar2(p_path => 'lovFilters[%d].values[%d]', p0 => lr_i, p1 => lr_n, p_values => l_json_values);
dbms_output.put_line ('filter_value : '||filter_value);
END LOOP;
END LOOP;
END;
Not sure what the problem was. Your code complained about l_json_values not being defined - maybe you copied some code from elsewhere ?
The following works:
DECLARE
l_json_text VARCHAR2(5000);
l_json_values apex_json.t_values;
l_array_count NUMBER := 0;
l_lov_for VARCHAR2(30);
l_filter_value VARCHAR2(256);
l_count_2 NUMBER:= 0;
BEGIN
l_json_text :=
'{
"lovFilters": [
{
"lovFor": "Ids",
"values": [1,2,3]
},
{
"lovFor": "Amounts",
"values": [20,30,50,60]
}
]
}';
apex_json.parse(
p_values => l_json_values,
p_source => l_json_text
);
l_array_count := APEX_JSON.get_count(p_path => 'lovFilters',p_values => l_json_values);
dbms_output.put_line ('FILTER array count : '||l_array_count);
FOR lr_i IN 1 .. l_array_count
LOOP
dbms_output.put_line ('-------------------------');
l_lov_for := APEX_JSON.get_varchar2 (p_path => 'lovFilters[%d].lovFor', p0 => lr_i, p_values => l_json_values);
dbms_output.put_line ('l_lov_for : '||l_lov_for);
l_count_2 := APEX_JSON.get_count(p_path => 'lovFilters[%d].values', p0 => lr_i, p_values => l_json_values);
dbms_output.put_line ('l_count_2 : '||l_count_2);
dbms_output.put_line ('--------------------------');
FOR lr_n IN 1 .. l_count_2
LOOP
l_filter_value :=
APEX_JSON.get_varchar2(p_path => 'lovFilters[%d].values[%d]', p0 => lr_i, p1 => lr_n, p_values => l_json_values);
dbms_output.put_line ('l_filter_value : '||l_filter_value);
END LOOP;
END LOOP;
END;
/
I have two lists of maps a and b.
a = [
%{"school" => "a", "class" => 1, "student" => "jane doe"},
%{"school" => "b", "class" => 9, "student" => "jane1 doe"},
%{"school" => "c", "class" => 6, "student" => "jane doe2"}
]
b = [
%{"choice" => "arts", "class" => 1, "school" => "a"},
%{"choice" => "science", "class" => 9, "school" => "a"},
%{"choice" => "maths", "class" => 6, "school" => "b"}
]
I want to be able to compare the two lists and produce a list with items of the following structure
desired_result = [
%{
"school" => "a",
"class" => 1,
"student" => "jane doe" or nil (if student exists only in list b but not in a),
"choices" => ["arts"] or [] (if student exists only in list a but not in b),
"is_common" => yes(if the student exists in both lists) OR only list a OR only list b
}
]
I have tried using the Enum.into and Enum.member? functions and I have been able to achieve 60% of the solution that I want.
Enum.into(a, [], fn item ->
if Enum.member?(b, %{
"school" => item["school"],
"class" => item["class"]
}) do
%{
"school" => item["school"],
"class" => item["class"],
"student" => item["student"],
"choices" => [],
"is_common" => "yes"
}
else
%{
"school" => item["school"],
"class" => item["class"],
"student" => item["student"],
"choices" => [],
"is_common" => "only list a"
}
end
end)
The problem with the above is that it covers the cases of the common ones in both lists and the ones that are only in list a; but it doesn't cover the ones that are only in list b. And also, I couldn't find a way to get the value of choice in my final result from list b (as you can see I left the value of "choice" as []). How to get all three cases covered and get a list in the desired structure with the values?
Let’s start with producing a bare result out of what you have. I assume the pair school + class is what the defines uniquity.
[a, b]
|> Enum.map(fn list ->
Enum.group_by(list, & {&1["class"], &1["school"]})
end)
|> Enum.reduce(
&Map.merge(&1, &2, fn _, [v1], [v2] -> [Map.merge(v1, v2)] end))
|> Enum.map(fn {_, [v]} -> v end)
#⇒ [
# %{"choice" => "arts", "class" => 1, "school" => "a", "student" => "jane doe"},
# %{"choice" => "maths", "class" => 6, "school" => "b"},
# %{"class" => 6, "school" => "c", "student" => "jane doe2"},
# %{"choice" => "science", "class" => 9, "school" => "a"},
# %{"class" => 9, "school" => "b", "student" => "jane1 doe"}
# ]
Feel free to run the above clause by clause to review all the transformations involved.
The list above guarantees the uniqueness by %{"school" => any(), "class" => any()} amongst list elements. Now simply iterate through and update elements according to your needs.
I will go with a different approach, trying to go through both lists using tail recursion.
In order to use this approach we need guarantee that both lists a and b will be ordered by the fields that allow us to make the match, in this case school and class.
This is needed because during the tail recursion we will be making the match between lists on the fly and it is mandatory to guarantee that if we are leaving an unmatched a element it is not possible to find an b match later
# With this both lists will be ordered ascendently by school and class fields.
ordered_a = Enum.sort(a, &((&1["school"] < &2["school"]) || (&1["class"] <= &2["class"] )))
ordered_b = Enum.sort(b, &((&1["school"] < &2["school"]) || (&1["class"] <= &2["class"] )))
With this both list will be ascending ordered by school and class fields.
Let's go with the hard part. Now we need to think about going through two ordered lists. The recursion will be done over the match_lists function.
We can have these 6 possibles pattern match of the headers:
[MATCH] The school and class fields of the Head of the two lists are the same, so they make a match. In this case we build the new element and add it to the accumulator. On next call we just pass the tail of both lists.
[UNMATCHED B] Head element of a is ahead Head element of b, this is school field (or class field if school is the same) has a bigger value. That means there is no match available for current Head element of list b since the list a is already ahead it. So an unmatched b element will be built and added to the accumulator. On next call we just passed the tail of b but the full a list.
[UNMATCHED A] Same that point 2 but respect to list a. The Head element of list b is ahead the Head element of list a. That means there is no match available for Head element in a since Head in b is already ahead. An unmatched a element will be build and added to the accumulator.
[UNMATCHED B] The list a is empty. An unmatched B will generated with the Head of band added to the accumulator.
[UNMATCHED A] The list b is empty. An unmatched A will generated with the Head of a and added to the accumulator.
[END] Both list are empty. The recursion has ended and the accumulator will be returned.
def match_lists(a, b, acc \\ [] )
# Case: Element in both lists
def match_lists(
[%{"school" => school, "class" => class, "student" => student} | rest_a],
[%{"school" => school, "class" => class, "choice" => choice} | rest_b],
acc
) do
element = build(school, class, student, [choice], true)
match_lists(rest_a, rest_b, [element | acc])
end
# Case: Element only in list B case. So it is a B case
def match_lists(
[%{"school" => school_a, "class" => class_a} | _] = a,
[%{"school" => school_b, "class" => class_b, "choice" => choice} | rest_b],
acc
)
when school_a > school_b or class_a > class_b do
element = build(school_b, class_b, nil, [choice], "only_list_b")
match_lists(a, rest_b, [element | acc])
end
# Case: No more elementes in A. So It is a B case
def match_lists([], [%{"school" => school, "class" => class, "choice" => choice} | rest_b], acc) do
element = build(school, class, nil, [choice], "only_list_b")
match_lists([], rest_b, [element | acc])
end
# Case: Element only in list A
def match_lists(
[%{"school" => school_a, "class" => class_a, "student" => student} | rest_a],
[%{"school" => school_b, "class" => class_b} | _] = b,
acc
)
when school_b > school_a or class_b > class_a do
element = build(school_a, class_a, student, [], "only_list_a")
match_lists(rest_a, b, [element | acc])
end
# Case: No more elementes in B. So It is an uncommon A case
def match_lists([%{"school" => school, "class" => class, "student" => student} | rest_a], [], acc) do
element = build(school, class, student, [], "only_list_a")
match_lists(rest_a, [], [element | acc])
end
def match_lists([], [], acc) do
acc
end
defp build(school, class, student, choices, is_common) do
%{
"school" => school,
"class" => class,
"student" => student,
"choices" => choices,
"is_common" => is_common
}
end
iex(1)> match_lists(ordered_a, ordered_b)
[
%{
"choices" => [],
"class" => 6,
"is_common" => "only_list_a",
"school" => "c",
"student" => "jane doe2"
},
%{
"choices" => [],
"class" => 9,
"is_common" => "only_list_a",
"school" => "b",
"student" => "jane1 doe"
},
%{
"choices" => ["maths"],
"class" => 6,
"is_common" => "only_list_b",
"school" => "b",
"student" => nil
},
%{
"choices" => ["science"],
"class" => 9,
"is_common" => "only_list_b",
"school" => "a",
"student" => nil
},
%{
"choices" => ["arts"],
"class" => 1,
"is_common" => true,
"school" => "a",
"student" => "jane doe"
}
]
Hope it helps.
The following property test is working fine, however, I think there should be a better and more efficient way of implementing this.
params in the following property will be something like this:
%{
"project_id" => "%&!XX!hLCfsS-dO_<fy?kpi4y=AEumQ$Xn:#.7Fl TnH~k>ZLB[q",
"task_id" => [
%{"asset_id" => 10, "tasks" => []},
%{"asset_id" => 10, "tasks" => []}
]
}
Property Testing:
property "bad project value" do
[user, project] = prepare()
user_gen = constant(%{id: user.id})
project_gen = constant("project_id")
|> map_of(Factory.my_terms, length: 1)
tasks = constant(%{"asset_id" => 10, "tasks" => []})
|> list_of(length: 2)
tasks_gen = constant("task_id")
|> map_of(tasks, length: 1)
check all project <- project_gen, task <- tasks_gen , user <- user_gen do
params = Map.merge(project, task)
res = ProjectTask.Save.save(params, user)
assert res == {:error, :not_found}
end
Factory.my_terms is the following:
def my_terms() do
one_of([string(:alphanumeric), string(:ascii), atom(:alphanumeric), integer(), binary()])
end
UPDATE
property "bad project value" do
[user, project] = prepare()
project_gen = constant("project_id")
|> map_of(Factory.my_terms, length: 1)
tasks = List.duplicate(%{"asset_id" => 10, "tasks" => []}, 2)
tasks = %{"tasks" => tasks}
check all project <- project_gen do
params = Map.merge(project, tasks)
res = ProjectTask.Save.save(params, %{id: user.id})
assert res == {:error, :not_found}
end
end
I have this problem:
I have this JavaScript code in a Dynamic Action:
var vMe = $(this.triggeringElement);
var vRow = $(vMe).parents(".meAllRow");
var vSeqID = $(vRow).find("[headers=SEQ_ID]").html();
var vEstado = $(vRow).find("[name=f01]").val();
apex.server.process("ajx_Cambia_estado",{x01:vSeqID,x02:vEstado});
and this is the PL-SQL CODE
DECLARE
vEstado VARCHAR2(1);
vSeq NUMBER := to_number(APEX_APPLICATION.g_x01);
BEGIN
IF (APEX_APPLICATION.g_x02 = 'A') THEN
vEstado := 'I';
ELSE
vEstado := 'A';
END IF;
APEX_COLLECTION.UPDATE_MEMBER (
p_collection_name => 'DINAMIC_LIST',
p_seq => vSeq,
p_c002 => vEstado);
END;
When I execute the dynamic action, it throws this error:
SyntaxError: Unexpected end of JSON
but when I put a return in the PL-SQL like:
htp.p('"process":"finish"');
the error disappears. But I don't need to send a response message, in Apex 4.2 I don't have this problem.
Try:
DECLARE
vEstado VARCHAR2(1);
vSeq NUMBER := to_number(APEX_APPLICATION.g_x01);
BEGIN
IF (APEX_APPLICATION.g_x02 = 'A') THEN
vEstado := 'I';
ELSE
vEstado := 'A';
END IF;
APEX_COLLECTION.UPDATE_MEMBER (
p_collection_name => 'DINAMIC_LIST',
p_seq => vSeq,
p_c002 => vEstado);
apex_json.open_object;
apex_json.write('success', true);
apex_json.close_object;
END;
I have an array in Sublime Text with every city in the U.S as the value and a code which includes the state abbreviation as the key. It looks a little something like this:
$array = array(
"United States of America" => array(
"USAK0001" => "Adak",
"USAK0002" => "Adak Island",
"USAK0003" => "Akiachak",
"USAK0004" => "Akiak",
"USAK0005" => "Akutan",
"USAK0006" => "Alakanuk",
"USAK0007" => "Aleknagik",
"USAK0008" => "Allakaket",
"USAL0028" => "Arlington",
"USAL0029" => "Ashford",
"USAL0030" => "Ashland",
"USAL0031" => "Ashville",
"USAL0032" => "Athens",
"USAL0033" => "Atmore",
"USAL0034" => "Attalla",
"USAL0035" => "Auburn",
"USAL0036" => "Auburn University",
"USAL0037" => "Autaugaville",
"USAL0038" => "Axis",
"USAL0039" => "Baileyton",
)
);
What I need to do is a search and replace to append the state name to the value, based on finding the two letter state abbreviation in the array key code.
So for example, a search that finds "AK" in the key and adds "Alaska" to the value, so they would look like this:
"USAK0001" => "Alaska, Adak",
"USAK0002" => "Alaska, Adak Island",
"USAK0003" => "Alaska, Akiachak",
"USAK0004" => "Alaska, Akiak",
"USAK0005" => "Alaska, Akutan",
"USAK0006" => "Alaska, Alakanuk",
Every key is 8 characters long, but I really don't even know how to begin trying to do this in Sublime Text.
Thanks to nhahtdh, I did this quite easily with a PHP script to merge it. It ended up being as simple as the below, with no need for regex! (Huzzah!)
function merge_states_into_cities( $states, $cities ) {
foreach ( $cities as $key => $array ) {
foreach ( $array as $code => $city ) {
foreach ( $states as $abbrv => $state ) {
if ( strpos( $code, $abbrv, 2 ) ) {
echo '"' . $code . '" => "' . $state . ', ' . $city . '",<br>';
}
}
}
}
}