英文:
From a hash map, How to replace different values into each "key" that appeared in the input sentence?
问题
我有一个哈希映射 HashMap<String, ArrayList<String>>
(例如 Person-[p1,p2,p3]
),
以及一个输入字符串:
"Person talked to Person about Person"
如何将不同的值替换到输入句子中出现的每个“key”中?
我希望结果应为:
"p1 talked to p2 about p3"
"p1 talked to p3 about p2"
"p2 talked to p1 about p3"
"p2 talked to p3 about p1"
"p3 talked to p2 about p1"
"p3 talked to p1 about p2"
(组合 n 中的 k 个元素的所有可能组合)。是否有任何方法或库支持此替换?
--
我已经完成了生成简单替换的步骤,但仍卡在生成排列的步骤。
public static void main (String[] args) {
HashMap<String, ArrayList<String>> data = new HashMap<>();
String test = "Person talked to Person about Person and Person";
//仅用于填充。
ArrayList<String> input = new ArrayList<>();
input.add("p1");
input.add("p2");
input.add("p3");
data.put("Person", input);
if (StringUtils.countMatches(test, "Person") > data.get("Person").size()) {
System.out.println("Error: out of range");
} else {
for (int i = 0; i < data.get("Person").size(); i++) {
myReplace(test, "Person", data, i);
}
}
}
public static void myReplace(String input, String replaceValue, HashMap<String, ArrayList<String>> data, int indexOfValue) {
while (input.contains(replaceValue)) {
if (indexOfValue >= data.get(replaceValue).size() - 1) {
indexOfValue = indexOfValue % data.get(replaceValue).size();
}
input = input.replaceFirst(replaceValue, data.get(replaceValue).get(indexOfValue));
indexOfValue++;
}
System.out.println(input);
}
英文:
I have a hashmap HashMap<String, ArrayList<String>>
(e.g. Person-[p1,p2,p3]
),
and an input string:
"Person talked to Person about Person"
How to replace different values into each "key" that appeared in the input sentence?
I want the result should be:
"p1 talked to p2 about p3"
"p1 talked to p3 about p2"
"p2 talked to p1 about p3"
"p2 talked to p3 about p1"
"p3 talked to p2 about p1"
"p3 talked to p1 about p2"
(combination all possible combinations of k elements in n). Is that any method or library support for this replacement?
--
I've done at the step of generating a simple replacing, but still stucked at generating the Permutations.
public static void main (String[] args) {
HashMap<String, ArrayList<String>> data = new HashMap<>();
String test = "Person talked to Person about Person and Person";
//Just to populate.
ArrayList<String> input = new ArrayList<>();
input.add("p1");
input.add("p2");
input.add("p3");
data.put("Person", input);
if (StringUtils.countMatches(test, "Person") > data.get("Person").size()) {
System.out.println("Error: out of range");
}else {
for (int i=0 ; i<data.get("Person").size() ; i++) {
myReplace(test, "Person", data, i);
}
}
}
public static void myReplace(String input, String replaceValue, HashMap<String, ArrayList<String>> data, int indexOfValue) {
while (input.contains(replaceValue)) {
if (indexOfValue >= data.get(replaceValue).size()-1) {
indexOfValue = indexOfValue % data.get(replaceValue).size();
}
input = input.replaceFirst(replaceValue, data.get(replaceValue).get(indexOfValue));
indexOfValue++;
}
System.out.println(input);
}
答案1
得分: 1
以下是翻译好的部分:
这里有一个建议。这部分是部分伪代码,因此无法编译。
关键是不使用映射,而是简单地生成人们交谈的排列。对于三个人,你有六种排列,四个人,24种排列,n个人,n!种排列。以下是三个人的排列:
p1, p2, p3
p1, p3, p2
p2, p1, p3
p2, p3, p1
p3, p1, p2
p3, p2, p1
因此在网络上搜索(或者本站)排列算法(有许多这样的算法),然后执行以下操作:
ArrayList<String> input = new ArrayList<>();
input.add("p1");
input.add("p2");
input.add("p3");
while(input = getNextPermutation(input)) {
String text = "Person talked to Person about Person";
for (String p : input) {
text.replaceFirst("Person", p);
}
System.out.println(text);
}
这里的主要挑战将是将排列算法整合到代码中。不必像示例中那样完成。
英文:
Here is a suggestion. This is partially pseudo code so it will not compile.
The key is not to use a map but to simply generate permutations of the people talking. For three people you have six permutations, four people, 24 permutations, n
people, n!
permutations. Here are the ones for three people:
p1, p2, p3
p1, p3, p2
p2, p1, p3
p2, p3, p1
p3, p1, p2
p3, p2, p1
So search the web (or this site) for a permutation algorithm (there are many out there) and do the following:
ArrayList<String> input = new ArrayList<>();
input.add("p1");
input.add("p2");
input.add("p3");
while(input = getNextPermutation(input)) {
String text = "Person talked to Person about Person";
for ( String p : input) {
text.replaceFirst("Person", p)
}
System.out.println(text);
}
The main challenge here will be integrating the permutation algorithm into the code. It does not have to be done as in the example.
答案2
得分: 1
关于接受答案和您初始代码的更详细评论 - 如果要真正实现一对多的移动,我不会使用List,而是使用Set(确保每个主题是唯一的)。
在另一种方法中,我只会在列表本身或者在我的情况下是数组本身上工作,一旦我知道结果是正确的,就保存结果。在我的情况下,这个数组不是一个“普通”的数组,它有一个额外的特性;数组具有令人恼火的“结束”属性,但这个数组可以旋转(我最初是将其用作在生成我想要“消失”的直方图桶时要“消失”的颜色的方法。后来在生成JUnits等测试数据时经常使用它,一个小数组可以生成任意数量的测试数据)。
在最简单的情况下,你只需要使用getNext(),当指针超过末尾索引时,它会重新回到0,基本上就是这样(我还为不同的目的添加了一些额外的抓取方法)。
一个JUnit测试示例:
public class SpeakerTest {
private static final String[] PERSONS = new String[] { "p1", "p2", "p3" };
private static final ArrayRotator<String> ROTATOR = new ArrayRotator<>(PERSONS);
private static final String NL = System.getProperty("line.separator");
private static final String SUBJECT_ = "subject ";
private static final String TALKED_TO = " talked to ";
@Test
public void everyoneGetsToSpeakToTheOthers() {
StringBuilder message = new StringBuilder();
int subjectIndex = 0; // 指向正在发言的主题
int personsTalkedTo = 0; // 每个人说过话的次数
while (subjectIndex < PERSONS.length) {
ROTATOR.getNext(); // 在我们有序的数组中,第一个人总是主题自己 - 跳过它
while (personsTalkedTo < PERSONS.length) {
String adressedPerson = ROTATOR.getNext();
if (personsTalkedTo != PERSONS.length - 1) { // 我们知道我们总是想抓取比实际长度少一个的数量
message.append(SUBJECT_).append(PERSONS[subjectIndex]).append(TALKED_TO).append(adressedPerson).append(NL);
}
personsTalkedTo++;
}
subjectIndex++; // 移动到下一个主题
personsTalkedTo = 0; //..迄今为止谁也没有说过话
// 只是打印出来然后重置构建器
System.out.println(message.toString());
message.delete(0, message.length());
}
}
}
产生输出:
subject p1 talked to p2
subject p1 talked to p3
subject p2 talked to p3
subject p2 talked to p1
subject p3 talked to p1
subject p3 talked to p2
并且对于任意数量的人都适用。如果要将结果保存在映射中,您可以在打印的地方做出相应的更改。
这个小工具 ArrayRotator
接受任何数组并在许多场景中都很有用:
public class ArrayRotator<T> {
// ... 省略了您提供的代码 ...
}
英文:
More of a detailed comment on the accepted answer and your initial code - to truly move this around one-to-many, I would not use List but Set instead (guaranteeing that each subject is unique) if doing it this way.
On a different approach, I would just be working on the list itself or in my case array itself saving results once I know it's correct. And the array is not a 'plain' array in my case, it has an extra feature; arrays have the irritating property of ending but this one can rotate (I initially used it as a way to fade colours when generating histogram buckets that I wanted to 'fade'. Then I started using it frequently when generating test data for JUnits etc, a small array can generate any amount of test data for instance). In the simplest case you just use getNext() and when the pointer has passed the end index it just reverts to 0 again and that's pretty much it (I added some extra grab methods for different purposes).
A JUnit:
public class SpeakerTest {
private static final String[] PERSONS = new String[] { "p1", "p2", "p3" };
private static final ArrayRotator<String> ROTATOR = new ArrayRotator<>(PERSONS);
private static final String NL = System.getProperty("line.separator");
private static final String SUBJECT_ = "subject ";
private static final String TALKED_TO = " talked to ";
@Test
public void everyoneGetsToSpeakToTheOthers() {
StringBuilder message = new StringBuilder();
int subjectIndex = 0; // points to the subject speaking
int personsTalkedTo = 0; // how many each has talked to
while (subjectIndex < PERSONS.length) {
ROTATOR.getNext(); // the first person is always the subject self in our ordered array - skip it
while (personsTalkedTo < PERSONS.length) {
String adressedPerson = ROTATOR.getNext();
if (personsTalkedTo != PERSONS.length - 1) { // we know we always want to grab one less than the actual length
message.append(SUBJECT_).append(PERSONS[subjectIndex]).append(TALKED_TO).append(adressedPerson).append(NL);
}
personsTalkedTo++;
}
subjectIndex++; // move to the next subject
personsTalkedTo = 0; //..which so far talked to noone
// just print it and reset the builder
System.out.println(message.toString());
message.delete(0, message.length());
}
}
}
produces output
subject p1 talked to p2
subject p1 talked to p3
subject p2 talked to p3
subject p2 talked to p1
subject p3 talked to p1
subject p3 talked to p2
and it will work for any number of persons. If you want to save results in a map you can do this instead of printing.
The little Rotator tool that you feed with any array of anything which, again, is useful for many purposes:
public class ArrayRotator<T> {
private final T[] array;
private int index;
private static final Random RANDOM = new Random(731111245);
private enum Direction {
FORWARD, BACKWARD
}
public enum RenderMethod {
NEXT, RANDOM, PHASED_NEXT
}
private Direction direction;
public ArrayRotator(T[] array) {
if (array == null || array.length < 2) {
throw new IllegalArgumentException("You need top ship an array of no less than 2 elements!");
}
this.array = array;
index = -1;
direction = Direction.FORWARD;
}
public T getNext() {
index++;
if (index > array.length - 1) {
index = 0;
}
return array[index];
}
public T getRandom() {
return array[RANDOM.nextInt((array.length - 1) + 1)];
}
public T getNextPhading() {
if (direction == Direction.FORWARD) {
index++;
} else {
index--;
if (index < 0) {
direction = Direction.FORWARD;
index++;
}
}
if (index > array.length - 1) {
direction = Direction.BACKWARD;
index--;
}
return array[index];
}
public T[] get(RenderMethod method, int numberOfItems) {
List<T> list = new ArrayList<>();
switch (method) {
case NEXT:
for (int i = 0; i < numberOfItems; i++) {
list.add(getNext());
}
return (T[]) list.toArray();
case RANDOM:
for (int i = 0; i < numberOfItems; i++) {
list.add(getRandom());
}
return (T[]) list.toArray();
case PHASED_NEXT:
for (int i = 0; i < numberOfItems; i++) {
list.add(getNextPhading());
}
return (T[]) list.toArray();
default: throw new RuntimeException(String.format("Not supported mode %s", method.name()));
}
}
}
答案3
得分: 0
以下是翻译后的代码部分:
public void test(){
String p1 = "P1";
String p2 = "P2";
String p3 = "P3";
List<String> personList = List.of(p1, p2, p3);
List<String> resultList = new ArrayList<>();
personList
.stream()
.forEach(px -> personList // 1st Loop over all Person List
.stream()
.filter(not(px::equals)) // Filter to exclude the px person
.forEach(py -> personList // 2nd loop over filtered Person List
.stream()
.filter(p -> !(p.equals(px) || p.equals(py))) // Filter to exclude both px and py
.forEach(pz -> // 3rd loop over filtered Person List
resultList.add(String.format("%s talked to %s about %s", px, py, pz))) // Prepare the result
)
);
for(String result: resultList) {
System.out.println(result);
}
}
生成的输出如下:
P1 talked to P2 about P3
P1 talked to P3 about P2
P2 talked to P1 about P3
P2 talked to P3 about P1
P3 talked to P1 about P2
P3 talked to P2 about P1
英文:
It is also possible to use Java Streams in this scenario and generate the needed result. Here is the working solution -
public void test(){
String p1 = "P1";
String p2 = "P2";
String p3 = "P3";
List<String> personList = List.of(p1, p2, p3);
List<String> resultList = new ArrayList<>();
personList
.stream()
.forEach(px -> personList // 1st Loop over all Person List
.stream()
.filter(not(px::equals)) // Filter to exclude the px person
.forEach(py -> personList // 2nd loop over filtered Person List
.stream()
.filter(p -> !(p.equals(px) || p.equals(py))) // Filter to exclude both px and py
.forEach(pz -> // 3rd loop over filtered Person List
resultList.add(String.format("%s talked to %s about %s", px, py, pz))) // Prepare the result
)
);
for(String result: resultList) {
System.out.println(result);
}
}
Generated Output
P1 talked to P2 about P3
P1 talked to P3 about P2
P2 talked to P1 about P3
P2 talked to P3 about P1
P3 talked to P1 about P2
P3 talked to P2 about P1
答案4
得分: -1
你可以使用replaceFirst来实现。并确保你只有三个输入
HashMap<String, ArrayList<String>> data = new HashMap<>();
//只是为了填充。
ArrayList<String> input = new ArrayList<>();
input.add("p1");
input.add("p2");
input.add("p3");
data.put("Person", input);
data.put("Person2", input);
data.put("Person3", input);
String test = "Person talked to Person about Person";
//填充结束
data.forEach((k, v) -> {
String newS = test.replaceFirst("Person", v.get(0));
newS = newS.replaceFirst("Person", v.get(1));
newS = newS.replaceFirst("Person", v.get(0));
System.out.println(newS);
});
英文:
You can do it using replaceFirst. And assuring you only have three inputs
HashMap<String, ArrayList<String>> data = new HashMap<>();
//Just to populate.
ArrayList<String> input = new ArrayList<>();
input.add("p1");
input.add("p2");
input.add("p3");
data.put("Person", input);
data.put("Person2", input);
data.put("Person3", input);
String test = "Person talked to Person about Person";
//End of populate
data.forEach((k, v) -> {
String newS = test.replaceFirst("Person", v.get(0));
newS = newS.replaceFirst("Person", v.get(1));
newS = newS.replaceFirst("Person", v.get(0));
System.out.println(newS);
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论