I'm new in go and tried to populate slice data by same values in GO.
Refer to the following example
input struct {
ID string `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
}
output struct {
ID string `json:"id"`
Name string `json:"name"`
Image []img `json:"image"`
}
img struct {
Name string `json:"name"`
Width int `json:"width"`
Height int `json:"height"`
}
input = [{
"id": 10,
"name": "product 10",
"image": {"name": "https://i.imgur.com/eKSk6Fq.jpg"}
}, {
"id": 10,
"name": "product 10",
"image": {"name": "https://i.imgur.com/np1wmxw.jpg"}
}, {
"id": 11,
"name": "product 11",
"image": {"name": "https://i.imgur.com/jlFgGpe.jpg"}
}, {
"id": 11,
"name": "product 11",
"image": {"name": "https://i.imgur.com/B0D4iRk.jpg"}
}, {
"id": 11,
"name": "product 11",
"image": {"name": "https://i.imgur.com/4AiXzf8.jpg"}
}]
// expected output
output = [{
"id": 10,
"name": "product 10",
"image": [{
"name": "https://i.imgur.com/eKSk6Fq.jpg",
"width": 900,
"height": 600
}, {
"name": "https://i.imgur.com/np1wmxw.jpg",
"width": 600,
"height": 600
}]
}, {
"id": 11,
"name": "product 11",
"image": [{
"name": "https://i.imgur.com/jlFgGpe.jpg",
"width": 639,
"height": 700
}, {
"name": "https://i.imgur.com/B0D4iRk.jpg",
"width": 1280,
"height": 960
}, {
"name": "https://i.imgur.com/4AiXzf8.jpg",
"width": 540,
"height": 405
}]
}]
I would like to group input to a new slice based on the same ID,
so the result output would be new slice of new struct with grouped image with same ID.
H̶o̶w̶ ̶w̶o̶u̶l̶d̶ ̶I̶ ̶a̶c̶h̶i̶e̶v̶e̶d̶ ̶t̶h̶e̶ ̶̶o̶u̶t̶p̶u̶t̶̶ ̶r̶e̶s̶u̶l̶t̶ ̶u̶s̶i̶n̶g̶ ̶G̶O̶? update: got the answer from Peter Eichelsheim
Also, if I had to ge image size in the input with http.get and want to use goroutine, how would I achieve the result? since my last code here playground not achieving the correct output (always get the last input)
note: I don't know why I get null in go playground, but in my laptop the result is: [{"id":11,"name":"product 11","image":[{"name":"https://i.imgur.com/B0D4iRk.jpg","width":1280,"height":960}]}]
In PHP, I would do something below to achieve the intended output.
foreach ($input as $key => $value) {
if (!isset($output[$value["id"]])) {
$output[$value["id"]] = [
"id" => $value["id"],
"name" => $value["name"],
"image" => [],
];
}
$get = getimagesize($value["image"]["name"]);
if ($get) {
$width = isset($get[0]) ? $get[0] : 0;
$height = isset($get[1]) ? $get[1] : 0;
}
$output[$value["id"]]["image"][$key] = [
"name" => $value["image"]["name"],
"width" => $width,
"height" => $height,
];
$output[$value["id"]]["image"] = array_values($output[$value["id"]]["image"]);
}
$output = array_values($output);
$json = json_encode($output, true);
echo $json;
Thanks
Here a little sample with sample json input, using map[int]output to club images into the same product ID.
package main
import (
"encoding/json"
"fmt"
"log"
)
type input struct {
ID int `json:"id"`
Name string `json:"name"`
Image img `json:"image"`
}
type output struct {
ID int `json:"id"`
Name string `json:"name"`
Image []img `json:"image"`
}
type img struct {
Name string `json:"name"`
}
func main() {
var jsoninput = []byte(`
[{
"id": 10,
"name": "product 10",
"image": {"name": "image 10a"}
}, {
"id": 10,
"name": "product 10",
"image": {"name": "image 10b"}
}, {
"id": 11,
"name": "product 11",
"image": {"name": "image 11a"}
}, {
"id": 11,
"name": "product 11",
"image": {"name": "image 11b"}
}, {
"id": 11,
"name": "product 11",
"image": {"name": "image 11c"}
}]`)
var inputs []input
err := json.Unmarshal(jsoninput, &inputs)
if err != nil {
log.Fatalln("could not Unmarshal:", err)
}
var outputlist = make(map[int]output)
for _, inp := range inputs {
outputlist[inp.ID] = output{inp.ID, inp.Name, append(outputlist[inp.ID].Image, inp.Image)}
}
var outputs []output
for _, outp := range outputlist{
outputs = append(outputs,outp)
}
jsonoutput, err := json.Marshal(outputs)
fmt.Println(string(jsonoutput))
}
var inputs []input // assuming the json has been unmarshalled correctly
outs := make(map[int]output)
// this will create a map, keyed by id, values are groups of inputs
for _, input := range inputs {
out, exists := outs[input.ID]
if !exists {
out = output{
ID: input.ID,
Name: input.Name,
}
}
out.Image = append(out.Image, img{Name: input.Name})
}
output := make([]output, len(outs))
var idx int
for key, out := range outs {
output[idx] = out
idx++
}
Related
JSON struct like below:
[
{
"sha": "eb08dc1940e073a5c40d8b53a5fd58760fde8f27",
"node_id": "C_kwDOHb9FrtoAKGViMDhkYzE5NDBlMDczYTVjNDBkOGI1M2E1ZmQ1ODc2MGZkZThmMjc",
"commit": {
"author": {
"name": "xxxx"
},
"committer": {
"name": "xxxxx"
},
"message": "update DownLoad_Stitch_ACM.py",
"tree": {
"sha": "a30aab98319846f0e86da4a39ec05786e04c0a4f",
"url": "xxxxx"
},
"url": "xxxxx",
"comment_count": 0,
"verification": {
"verified": false,
"reason": "unsigned",
"signature": null,
"payload": null
}
},
"url": "xxxxx",
"html_url": "xxxxx",
"comments_url": "xxxxx",
"author": {
"login": "xxxxx",
"id": "xxxxx",
"node_id": "U_kgDOBkuicQ",
"avatar_url": "https://avatars.githubusercontent.com/u/105620081?v=4",
"gravatar_id": "",
"type": "User",
"site_admin": false
},
"committer": {
"login": "xxxxx",
"id": "xxxxx"
},
"parents": [
{
"sha": "cf867ec9dc4b904c466d9ad4b9338616d1213a06",
"url": "xxxxx",
"html_url": "xxxxx"
}
]
}
]
I don't know how to get the location 0's data.
content, _ := simplejson.NewJson(body)
arr, _ := content.Array() // Here can get the all data, It's []interface{} type.
I cannot get the next data with arr[0]["sha"]. How to handle it?
It is not clear to the compiler that arr is an array of map[string]interface{} at compile time, as arr[0] is of type interface{}. This basically means that the compiler knows nothing about this type, which is why you can't do a map lookup operation here.
You can add a type assertion to make sure you can use it as a map like this:
asMap := arr[0].(map[string]interface{})
fmt.Println(asMap["sha"])
To get the SHA as string, you can again add a type assertion behind it as well:
asString := asMap["sha"].(string)
This is also shown in this working example. The downside of this is that your program will panic in case the given data is not of the specified type. You could instead use a type assertion with a check if it worked (asString, ok := ...), but it gets cumbersome with more complex data.
This does work, but isn't really nice. I would recommend using a tool like this to generate Go structs and then use them in a type-safe way. First define a struct with all the info you need:
type ArrayElement struct {
Sha string `json:"sha"`
// Add more fields if you need them
}
Then you can just use the standard-library json package to unmarshal your data:
// This should have the same structure as the data you want to parse
var result []ArrayElement
err := json.Unmarshal([]byte(str), &result)
if err != nil {
panic(err)
}
fmt.Println(result[0].Sha)
Here is an example for that -- this is a more Go-like approach for converting JSON data.
Your json data is wrong formatted. First of all, remove , after "id": "xxxxx", line:
...
"id": "xxxxx"
...
You should check errors after NewJson to prevent find out if there is a problem:
content, err := simplejson.NewJson(body)
if err != nil {
// log err
}
For getting sha from first index, you simply can use simplejson built-in methods:
shaVal := content.GetIndex(0).Get("sha").String()
Here is how you can get the desired value.
This worked for me.
package main
import (
"encoding/json"
"fmt"
)
type MyData []struct {
Sha string `json:"sha"`
NodeID string `json:"node_id"`
Commit struct {
Author struct {
Name string `json:"name"`
} `json:"author"`
Committer struct {
Name string `json:"name"`
} `json:"committer"`
Message string `json:"message"`
Tree struct {
Sha string `json:"sha"`
URL string `json:"url"`
} `json:"tree"`
URL string `json:"url"`
CommentCount int `json:"comment_count"`
Verification struct {
Verified bool `json:"verified"`
Reason string `json:"reason"`
Signature interface{} `json:"signature"`
Payload interface{} `json:"payload"`
} `json:"verification"`
} `json:"commit"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
CommentsURL string `json:"comments_url"`
Author struct {
Login string `json:"login"`
ID string `json:"id"`
NodeID string `json:"node_id"`
AvatarURL string `json:"avatar_url"`
GravatarID string `json:"gravatar_id"`
Type string `json:"type"`
SiteAdmin bool `json:"site_admin"`
} `json:"author"`
Committer struct {
Login string `json:"login"`
ID string `json:"id"`
} `json:"committer"`
Parents []struct {
Sha string `json:"sha"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
} `json:"parents"`
}
func main() {
my_json_data := `[
{
"sha": "eb08dc1940e073a5c40d8b53a5fd58760fde8f27",
"node_id": "C_kwDOHb9FrtoAKGViMDhkYzE5NDBlMDczYTVjNDBkOGI1M2E1ZmQ1ODc2MGZkZThmMjc",
"commit": {
"author": {
"name": "xxxx"
},
"committer": {
"name": "xxxxx"
},
"message": "update DownLoad_Stitch_ACM.py",
"tree": {
"sha": "a30aab98319846f0e86da4a39ec05786e04c0a4f",
"url": "xxxxx"
},
"url": "xxxxx",
"comment_count": 0,
"verification": {
"verified": false,
"reason": "unsigned",
"signature": null,
"payload": null
}
},
"url": "xxxxx",
"html_url": "xxxxx",
"comments_url": "xxxxx",
"author": {
"login": "xxxxx",
"id": "xxxxx",
"node_id": "U_kgDOBkuicQ",
"avatar_url": "https://avatars.githubusercontent.com/u/105620081?v=4",
"gravatar_id": "",
"type": "User",
"site_admin": false
},
"committer": {
"login": "xxxxx",
"id": "xxxxx"
},
"parents": [
{
"sha": "cf867ec9dc4b904c466d9ad4b9338616d1213a06",
"url": "xxxxx",
"html_url": "xxxxx"
}
]
}]`
var data MyData
err := json.Unmarshal([]byte(my_json_data), &data)
if err != nil {
panic(err)
}
fmt.Println("data --> sha: ", data[0].Sha)
}
I have a struct like that.
type Category struct {
ID int `json:"id"`
MetaDescription string `json:"metaDescription" gorm:"column:metadescription"`
MetaTitle string `json:"metaTitle" gorm:"column:metatitle"`
Name string `json:"name" gorm:"column:categoryname"`
Order int `json:"order" gorm:"column:categoryorder"`
ParentId int `json:"parentId" gorm:"column:parentid"`
Rank float64 `json:"rank" gorm:"column:rank"`
Url string `json:"url" gorm:"column:catname4seo"`
}
I'm fetching this data from a database and I want to manipulate it to create a category tree. My tree would be like that
type CategoryTree struct {
ID int `json:"id"`
Name string `json:"name" gorm:"column:categoryname"`
Url string `json:"url" gorm:"column:catname4seo"`
SubCategories []CategoryTree `json:"subCategories"`
}
Normally, I am a JavaScript dev and a newbie in GoLang so especially static type made me harder. That's why I couldn't achieve it. Can you help me to do so?
Thanks in advance.
I think this is an algorithm question. Just iterating over the Category list, and push elements into CategoryTree. Go code like this:
package main
import (
"encoding/json"
"fmt"
)
type Category struct {
ID int `json:"id"`
MetaDescription string `json:"metaDescription" gorm:"column:metadescription"`
MetaTitle string `json:"metaTitle" gorm:"column:metatitle"`
Name string `json:"name" gorm:"column:categoryname"`
Order int `json:"order" gorm:"column:categoryorder"`
ParentId int `json:"parentId" gorm:"column:parentid"`
Rank float64 `json:"rank" gorm:"column:rank"`
Url string `json:"url" gorm:"column:catname4seo"`
}
// load db data by CategoryTree instead of Category
type CategoryTree struct {
Category
SubCategories []*CategoryTree `json:"subCategories"`
}
func main() {
input := []*CategoryTree{
{
Category: Category{
ID: 1,
ParentId: 0,
},
},
{
Category: Category{
ID: 2,
ParentId: 1,
},
},
{
Category: Category{
ID: 3,
ParentId: 1,
},
},
{
Category: Category{
ID: 4,
ParentId: 2,
},
},
}
tree := makeTree(input)
output, _ := json.MarshalIndent(tree, "", " ")
fmt.Printf("%s\n", string(output))
}
func makeTree(list []*CategoryTree) *CategoryTree {
dataMap := make(map[int]*CategoryTree, len(list))
var rootNode *CategoryTree
for i := range list {
// root node has min ParentID
if rootNode == nil || rootNode.ParentId > list[i].ParentId {
rootNode = list[i]
}
// list to map
dataMap[list[i].ID] = list[i]
}
// build tree
for i := range list {
parentNode, ok := dataMap[list[i].ParentId]
if !ok {
continue
}
if parentNode.SubCategories == nil {
parentNode.SubCategories = []*CategoryTree{}
}
parentNode.SubCategories = append(parentNode.SubCategories, list[i])
}
return rootNode
}
and output:
{
"id": 1,
"metaDescription": "",
"metaTitle": "",
"name": "",
"order": 0,
"parentId": 0,
"rank": 0,
"url": "",
"subCategories": [
{
"id": 2,
"metaDescription": "",
"metaTitle": "",
"name": "",
"order": 0,
"parentId": 1,
"rank": 0,
"url": "",
"subCategories": [
{
"id": 4,
"metaDescription": "",
"metaTitle": "",
"name": "",
"order": 0,
"parentId": 2,
"rank": 0,
"url": "",
"subCategories": null
}
]
},
{
"id": 3,
"metaDescription": "",
"metaTitle": "",
"name": "",
"order": 0,
"parentId": 1,
"rank": 0,
"url": "",
"subCategories": null
}
]
}
I have struct:
type Book struct {
gorm.Model
Title string `json:"title"`
Author string `json:"author"`
Description string `json:"description"`
Category string `json:"Category"`
Publisher string `json:"publisher"`
AuthorsCard AuthorsCard `gorm:"foreignKey:BookID" json:"authorscard"`
}
type AuthorsCard struct {
//gorm.Model // I purposely Don't want to use gorm.model
ID uint `gorm:"primarykey"`
BookID uint
Name string `json:"name"`
Age int `json:"age"`
YearOfBirth int `json:"year"`
Biography string `json:"biography"`
}
And I'm trying to make update function:
// controller.go
func UpdateBook(ctx *gin.Context) {
enableCors(&ctx.Writer)
id := ctx.Param("ID")
var updateBook = &models.Book{}
if err := ctx.BindJSON(updateBook); err != nil {
ctx.AbortWithStatus(http.StatusBadRequest)
log.Fatal(err)
} else {
repository.UpdateBook(updateBook, id)
ctx.JSON(http.StatusOK, updateBook)
log.Println(updateBook)
}
}
//repository.go
func UpdateBook(updateBook *models.Book, ID string) {
book, db := GetBookById(ID)
if updateBook.Title != "" {
book.Title = updateBook.Title
}
if updateBook.Author != "" {
book.Author = updateBook.Author
}
if updateBook.Publisher != "" {
book.Publisher = updateBook.Publisher
}
if updateBook.Description != "" {
book.Description = updateBook.Description
}
if updateBook.Category != "" {
book.Category = updateBook.Category
}
if updateBook.AuthorsCard.Name != "" {
book.AuthorsCard.Name = updateBook.AuthorsCard.Name
}
if updateBook.AuthorsCard.Age != 0 {
book.AuthorsCard.Age = updateBook.AuthorsCard.Age
}
if updateBook.AuthorsCard.YearOfBirth != 0 {
book.AuthorsCard.YearOfBirth = updateBook.AuthorsCard.YearOfBirth
}
if updateBook.AuthorsCard.Biography != "" {
book.AuthorsCard.Biography = updateBook.AuthorsCard.Biography
}
db.Save(&book)
// same with db.Preload("AuthorsCard").Save(&book)
}
The issue is: When I make an PUT request, I receive Fully updated data. And when I'm trying to make GET request all my fields, except related AuthorsCard, are been updated.
PUT response:
200 Code
{
"ID": 0,
"CreatedAt": "0001-01-01T00:00:00Z",
"UpdatedAt": "0001-01-01T00:00:00Z",
"DeletedAt": null,
"title": "Test",
"author": "author",
"description": "something",
"Category": "Category",
"publisher": "PB",
"authorscard": {
"ID": 0,
"BookID": 0,
"name": "Updated",
"age": 22,
"year": 1999,
"biography": "biography Updated"
}
}
Get response after that:
[
{
"ID": 1,
"CreatedAt": "2022-06-29T14:57:37.489639+03:00",
"UpdatedAt": "2022-06-29T15:50:11.578724+03:00",
"DeletedAt": null,
"title": "Test",
"author": "author",
"description": "something",
"Category": "Category",
"publisher": "PB",
"authorscard": {
"ID": 1,
"BookID": 1,
"name": "test",
"age": 23,
"year": 1999,
"biography": "23fdgsdddTEST"
}
}
]
As you can see "authorscard" hasn't changed. Please, can someone tell me what I'm doing wrong?
You need to explicitly tell Gorm to store/update associations.
db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&book)
I have the following JSOn response from a webhook call
{
"responseId": "d5c70d8b-e8ad-41df-bb3b-26b0e51d60ca-a14fa99c",
"queryResult": {
"queryText": "1111111111",
"parameters": {
"phone-number": "1111111111"
},
"allRequiredParamsPresent": true,
"fulfillmentText": "Thats great! You payment link has been sent to Gaf ( Mobile number 1111111111 )",
"fulfillmentMessages": [{
"text": {
"text": ["Thats great! You payment link has been sent to Far ( Mobile number 1111111111 )"]
}
}],
"outputContexts": [{
"name": "projects/open-prod-bot-pfgibi/agent/sessions/80f2fb70-01d0-fc1d-200a-ccbae5572829/contexts/awaiting_name",
"lifespanCount": 2,
"parameters": {
"name": ["Gar"],
"name.original": ["Gar"],
"phone-number": "1111111111",
"phone-number.original": "1111111111"
}
}, {
"name": "projects/open-prod-bot-pfgibi/agent/sessions/80f2fb70-01d0-fc1d-200a-ccbae5572829/contexts/awaiting_number",
"lifespanCount": 4,
"parameters": {
"phone-number": "1111111111",
"phone-number.original": "1111111111"
}
}, {
"name": "projects/open-prod-bot-pfgibi/agent/sessions/80f2fb70-01d0-fc1d-200a-ccbae5572829/contexts/awaiting_name_confirm",
"lifespanCount": 3,
"parameters": {
"name": ["Gaf"],
"name.original": ["Far"],
"phone-number": "1111111111",
"phone-number.original": "1111111111"
}
}, {
"name": "projects/open-prod-bot-pfgibi/agent/sessions/80f2fb70-01d0-fc1d-200a-ccbae5572829/contexts/__system_counters__",
"parameters": {
"no-input": 0.0,
"no-match": 0.0,
"phone-number": "1111111111",
"phone-number.original": "1111111111"
}
}],
"intent": {
"name": "projects/open-prod-bot-pfgibi/agent/intents/d21f7be5-0f77-4cb8-9857-26ba04964317",
"displayName": "GetMobileNumber"
},
"intentDetectionConfidence": 1.0,
"languageCode": "en"
},
"originalDetectIntentRequest": {
"payload": {
}
},
"session": "projects/open-prod-bot-pfgibi/agent/sessions/80f2fb70-01d0-fc1d-200a-ccbae5572829"
}
I wanted to extract out
"outputContexts": [{
"name": "projects/open-prod-bot-pfgibi/agent/sessions/80f2fb70-01d0-fc1d-200a-ccbae5572829/contexts/awaiting_name",
"lifespanCount": 2,
"parameters": {
"name": ["Gar"],
"name.original": ["Gar"],
"phone-number": "1111111111",
"phone-number.original": "1111111111"
}
}
out of this and bind this with a struct. But I couldn't do it. I am trying to loop it through the map as below
var f interface{}
json.Unmarshal(b, &f)
for k, v := range f.(map[string]interface{}) {
if k == "queryResultmap" {
fmt.Println(v)
}
}
but not working. I am new to Go. Tried few examples in google but since this one is a complicated JSON I am unable to do it. Please help
I would suggest you declare a struct with the fields you care about and unmarshal into that, but if you want to stick to interface{} try this:
m := f.(map[string]interface{})
r := m["queryResult"].(map[string]interface{})
fmt.Println(r["outputContext"])
https://play.golang.com/p/gA5wWcPyd6E
Using struct:
type OutputContext struct {
Name string `json:"name"`
LifespanCount int `json:"lifespanCount"`
Parameters struct {
Name []string `json:"name"`
NameOriginal []string `json:"name.original"`
PhoneNumber string `json:"phone-number"`
PhoneNumberOriginal string `json:"phone-number.original"`
NoInput float64 `json:"no-input"`
NoMatch float64 `json:"no-match"`
} `json:"parameters"`
}
type QueryResult struct {
OutputContexts []OutputContext `json:"outputContexts"`
}
// ...
var dest struct {
QueryResult QueryResult `json:"queryResult"`
}
if err := json.Unmarshal(data, &dest); err != nil {
panic(err)
}
for _, v := range dest.QueryResult.OutputContexts {
fmt.Printf("%+v\n", v)
}
https://play.golang.com/p/EfIugDQJ651
I am trying to filter an original map by comparing with a condition map which has only the key sets with id. Based on the condition map, I want to filter from the original map.
The original map which I have is,
Map<Integer, AppFeatureDTO> appFeatureMap = new TreeMap<>();
which will result like,
{
"101": {
"id": 101,
"subFeature": {
"1": {
"id": 1,
"title": "Title Value",
"desc": "Description Value"
}
}
},
"102": {
"id": 102,
"subFeature": {
"1": {
"id": 1,
"title": "Title Value",
"desc": "Description Value"
}
}
},
"103": {
"id": 103,
"subFeature": {
"1": {
"id": 1,
"title": "Title Value",
"desc": "Description Value"
},
"2": {
"id": 2,
"title": "Title Value",
"desc": "Description Value"
},
"3": {
"id": 3,
"title": "Title Value",
"desc": "Description Value"
},
"4": {
"id": 4,
"title": "Title Value",
"desc": "Description Value"
}
}
}
}
and the corresponding classes are:
class AppFeatureDTO {
private int id;
private Map<Integer, AppSubFeatureDTO> subFeature;
}
class AppSubFeatureDTO{
private int id;
private String title;
private String description;
}
then I have a filter map,
Map<Integer, FeatureDTO> conditionFilterMap = new TreeMap<>();
which is resulting like,
{
"101": {
"id": 101,
"subFeature": {
"1": {
"id": 1,
}
}
},
"103": {
"id": 103,
"subFeature": {
"2": {
"id": 2
},
"4": {
"id": 4
}
}
}
}
the corresponding classes for the filter map are,
class FeatureDTO {
private int id;
private Map<Integer, SubFeatureDTO> subFeature;
}
class SubFeatureDTO{
private int id;
}
I want to filter the result map using conditionFilterMap like,
{
"101": {
"id": 101,
"subFeature": {
"1": {
"id": 1,
"title": "Title Value",
"desc": "Description Value"
}
}
},
"103": {
"id": 103,
"subFeature": {
"2": {
"id": 2,
"title": "Title Value",
"desc": "Description Value"
},
"4": {
"id": 4,
"title": "Title Value",
"desc": "Description Value"
}
}
}
}
I'm using spring modelMapper to copy AppFeatureDTO to FeatureDTO. But, filtering the map, I didn't get clue.
Could you please suggest how to get the resultMap using Java 8?
Even I couldn't imagine a simple solution using Java 7 or 6 also.
Assuming that the map key is the same as the id field:
Map<Integer, AppFeatureDTO> resultMap = conditionFilterMap.values().stream()
.map(FeatureDTO::getId)
.map(appFeatureMap::get)
.collect(Collectors.toMap(AppFeatureDTO::getId, a -> new AppFeatureDTO(a.getId(),
conditionFilterMap.get(a.getId()).getSubFeature().values().stream()
.map(SubFeatureDTO::getId)
.map(a.getSubFeature()::get)
.collect(Collectors.toMap(AppSubFeatureDTO::getId, x -> x)))));
If you need TreeMap, add the arguments (a, b) -> a, TreeMap::new to the Collectors.toMap calls.
The non-stream version doesn't really look any worse:
Map<Integer, AppFeatureDTO> resultMap = new TreeMap<>();
for (FeatureDTO f : conditionFilterMap.values()) {
AppFeatureDTO a = appFeatureMap.get(f.getId());
Map<Integer, AppSubFeatureDTO> resultSub = new TreeMap<>();
for (SubFeatureDTO s : f.getSubFeature().values()) {
resultSub.put(s.getId(), a.getSubFeature().get(s.getId()));
}
resultMap.put(a.getId(), new AppFeatureDTO(a.getId(), resultSub));
}